diff --git a/benchmark/pom.xml b/benchmark/pom.xml
index a337237a..30e834ac 100644
--- a/benchmark/pom.xml
+++ b/benchmark/pom.xml
@@ -27,13 +27,34 @@
com.netflix.feign
- feign-jaxrs
+ feign-okhttp
${project.version}
- javax.ws.rs
- jsr311-api
- 1.1.1
+ com.squareup.okhttp
+ mockwebserver
+ 2.3.0
+
+
+ org.bouncycastle
+ bcprov-jdk15on
+
+
+
+
+ io.reactivex
+ rxnetty
+ 0.4.8
+
+
+ io.reactivex
+ rxjava
+ 1.0.9
+
+
+ io.netty
+ netty-codec-http
+ 4.0.26.Final
org.openjdk.jmh
diff --git a/benchmark/src/main/java/feign/benchmark/ContractBenchmarks.java b/benchmark/src/main/java/feign/benchmark/ContractBenchmarks.java
deleted file mode 100644
index 4ac6c112..00000000
--- a/benchmark/src/main/java/feign/benchmark/ContractBenchmarks.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package feign.benchmark;
-
-import org.openjdk.jmh.annotations.Benchmark;
-import org.openjdk.jmh.annotations.BenchmarkMode;
-import org.openjdk.jmh.annotations.Fork;
-import org.openjdk.jmh.annotations.Measurement;
-import org.openjdk.jmh.annotations.Mode;
-import org.openjdk.jmh.annotations.OutputTimeUnit;
-import org.openjdk.jmh.annotations.Scope;
-import org.openjdk.jmh.annotations.Setup;
-import org.openjdk.jmh.annotations.State;
-import org.openjdk.jmh.annotations.Warmup;
-
-import java.util.concurrent.TimeUnit;
-
-import feign.Contract;
-import feign.jaxrs.JAXRSContract;
-
-@Measurement(iterations = 5, time = 1)
-@Warmup(iterations = 5, time = 1)
-@Fork(3)
-@BenchmarkMode(Mode.Throughput)
-@OutputTimeUnit(TimeUnit.SECONDS)
-@State(Scope.Thread)
-public class ContractBenchmarks {
-
- private Contract feignContract;
- private Contract jaxrsContract;
-
- @Setup
- public void setup() {
- feignContract = new Contract.Default();
- jaxrsContract = new JAXRSContract();
- }
-
- @Benchmark
- public void parseFeign() {
- feignContract.parseAndValidatateMetadata(FeignTestInterface.class);
- }
-
- @Benchmark
- public void parseJAXRS() {
- jaxrsContract.parseAndValidatateMetadata(JAXRSTestInterface.class);
- }
-
-}
diff --git a/benchmark/src/main/java/feign/benchmark/FeignTestInterface.java b/benchmark/src/main/java/feign/benchmark/FeignTestInterface.java
index d2063119..bfe66619 100644
--- a/benchmark/src/main/java/feign/benchmark/FeignTestInterface.java
+++ b/benchmark/src/main/java/feign/benchmark/FeignTestInterface.java
@@ -2,8 +2,6 @@ package feign.benchmark;
import java.util.List;
-import javax.ws.rs.HeaderParam;
-
import feign.Body;
import feign.Headers;
import feign.Param;
@@ -35,5 +33,5 @@ interface FeignTestInterface {
@RequestLine("POST /")
@Headers({"Happy: sad", "Auth-Token: {authToken}"})
- void headers(@HeaderParam("authToken") String token);
+ void headers(@Param("authToken") String token);
}
diff --git a/benchmark/src/main/java/feign/benchmark/JAXRSTestInterface.java b/benchmark/src/main/java/feign/benchmark/JAXRSTestInterface.java
deleted file mode 100644
index 5889f963..00000000
--- a/benchmark/src/main/java/feign/benchmark/JAXRSTestInterface.java
+++ /dev/null
@@ -1,57 +0,0 @@
-package feign.benchmark;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-import java.util.List;
-
-import javax.ws.rs.Consumes;
-import javax.ws.rs.FormParam;
-import javax.ws.rs.GET;
-import javax.ws.rs.HeaderParam;
-import javax.ws.rs.HttpMethod;
-import javax.ws.rs.POST;
-import javax.ws.rs.PUT;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.Produces;
-import javax.ws.rs.QueryParam;
-
-import feign.Headers;
-import feign.Response;
-
-@Consumes("application/json")
-interface JAXRSTestInterface {
-
- @GET
- @Path("/?Action=GetUser&Version=2010-05-08&limit=1")
- Response query();
-
- @GET
- @Path("/domains/{domainId}/records")
- Response mixedParams(@PathParam("domainId") int id, @QueryParam("name") String nameFilter,
- @QueryParam("type") String typeFilter);
-
- @PATCH
- Response customMethod();
-
- @Target({ElementType.METHOD})
- @Retention(RetentionPolicy.RUNTIME)
- @HttpMethod("PATCH")
- @interface PATCH {
-
- }
-
- @PUT
- @Produces("application/json")
- void bodyParam(List body);
-
- @POST
- void form(@FormParam("customer_name") String customer, @FormParam("user_name") String user,
- @FormParam("password") String password);
-
- @POST
- @Headers("Happy: sad")
- void headers(@HeaderParam("Auth-Token") String token);
-}
diff --git a/benchmark/src/main/java/feign/benchmark/RealRequestBenchmarks.java b/benchmark/src/main/java/feign/benchmark/RealRequestBenchmarks.java
new file mode 100644
index 00000000..fdbd401f
--- /dev/null
+++ b/benchmark/src/main/java/feign/benchmark/RealRequestBenchmarks.java
@@ -0,0 +1,85 @@
+package feign.benchmark;
+
+import com.squareup.okhttp.OkHttpClient;
+import com.squareup.okhttp.Request;
+
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.BenchmarkMode;
+import org.openjdk.jmh.annotations.Fork;
+import org.openjdk.jmh.annotations.Measurement;
+import org.openjdk.jmh.annotations.Mode;
+import org.openjdk.jmh.annotations.OutputTimeUnit;
+import org.openjdk.jmh.annotations.Scope;
+import org.openjdk.jmh.annotations.Setup;
+import org.openjdk.jmh.annotations.State;
+import org.openjdk.jmh.annotations.TearDown;
+import org.openjdk.jmh.annotations.Warmup;
+
+import java.io.IOException;
+import java.util.concurrent.TimeUnit;
+
+import feign.Feign;
+import feign.Response;
+import io.netty.buffer.ByteBuf;
+import io.reactivex.netty.RxNetty;
+import io.reactivex.netty.protocol.http.server.HttpServer;
+import io.reactivex.netty.protocol.http.server.HttpServerRequest;
+import io.reactivex.netty.protocol.http.server.HttpServerResponse;
+import io.reactivex.netty.protocol.http.server.RequestHandler;
+
+@Measurement(iterations = 5, time = 1)
+@Warmup(iterations = 10, time = 1)
+@Fork(3)
+@BenchmarkMode(Mode.Throughput)
+@OutputTimeUnit(TimeUnit.SECONDS)
+@State(Scope.Benchmark)
+public class RealRequestBenchmarks {
+
+ private static final int SERVER_PORT = 8765;
+ private HttpServer server;
+ private OkHttpClient client;
+ private FeignTestInterface okFeign;
+ private Request queryRequest;
+
+ @Setup
+ public void setup() {
+ server = RxNetty.createHttpServer(SERVER_PORT, new RequestHandler() {
+ public rx.Observable handle(HttpServerRequest request,
+ HttpServerResponse response) {
+ return response.flush();
+ }
+ });
+ server.start();
+ client = new OkHttpClient();
+ client.setRetryOnConnectionFailure(false);
+ okFeign = Feign.builder()
+ .client(new feign.okhttp.OkHttpClient(client))
+ .target(FeignTestInterface.class, "http://localhost:" + SERVER_PORT);
+ queryRequest = new Request.Builder()
+ .url("http://localhost:" + SERVER_PORT + "/?Action=GetUser&Version=2010-05-08&limit=1")
+ .build();
+ }
+
+ @TearDown
+ public void tearDown() throws InterruptedException {
+ server.shutdown();
+ }
+
+ /**
+ * How fast can we execute get commands synchronously?
+ */
+ @Benchmark
+ public com.squareup.okhttp.Response query_baseCaseUsingOkHttp() throws IOException {
+ com.squareup.okhttp.Response result = client.newCall(queryRequest).execute();
+ result.body().close();
+ return result;
+ }
+
+ /**
+ * How fast can we execute get commands synchronously using Feign?
+ */
+ @Benchmark
+ public Response query_feignUsingOkHttp() {
+ return okFeign.query();
+ }
+}
diff --git a/benchmark/src/main/java/feign/benchmark/WhatShouldWeCacheBenchmarks.java b/benchmark/src/main/java/feign/benchmark/WhatShouldWeCacheBenchmarks.java
new file mode 100644
index 00000000..239e7b75
--- /dev/null
+++ b/benchmark/src/main/java/feign/benchmark/WhatShouldWeCacheBenchmarks.java
@@ -0,0 +1,109 @@
+package feign.benchmark;
+
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.BenchmarkMode;
+import org.openjdk.jmh.annotations.Fork;
+import org.openjdk.jmh.annotations.Measurement;
+import org.openjdk.jmh.annotations.Mode;
+import org.openjdk.jmh.annotations.OutputTimeUnit;
+import org.openjdk.jmh.annotations.Scope;
+import org.openjdk.jmh.annotations.Setup;
+import org.openjdk.jmh.annotations.State;
+import org.openjdk.jmh.annotations.Warmup;
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+import feign.Client;
+import feign.Contract;
+import feign.Feign;
+import feign.MethodMetadata;
+import feign.Request;
+import feign.Response;
+import feign.Target.HardCodedTarget;
+
+@Measurement(iterations = 5, time = 1)
+@Warmup(iterations = 10, time = 1)
+@Fork(3)
+@BenchmarkMode(Mode.Throughput)
+@OutputTimeUnit(TimeUnit.SECONDS)
+@State(Scope.Thread)
+public class WhatShouldWeCacheBenchmarks {
+
+ private Contract feignContract;
+ private Contract cachedContact;
+ private Client fakeClient;
+ private Feign cachedFakeFeign;
+ private FeignTestInterface cachedFakeApi;
+
+ @Setup
+ public void setup() {
+ feignContract = new Contract.Default();
+ cachedContact = new Contract() {
+ private final List cached =
+ new Default().parseAndValidatateMetadata(FeignTestInterface.class);
+
+ public List parseAndValidatateMetadata(Class> declaring) {
+ return cached;
+ }
+ };
+ fakeClient = new Client() {
+ public Response execute(Request request, Request.Options options) throws IOException {
+ Map> headers = new LinkedHashMap>();
+ return Response.create(200, "ok", headers, (byte[]) null);
+ }
+ };
+ cachedFakeFeign = Feign.builder().client(fakeClient).build();
+ cachedFakeApi = cachedFakeFeign.newInstance(
+ new HardCodedTarget(FeignTestInterface.class, "http://localhost"));
+ }
+
+ /**
+ * How fast is parsing an api interface?
+ */
+ @Benchmark
+ public List parseFeignContract() {
+ return feignContract.parseAndValidatateMetadata(FeignTestInterface.class);
+ }
+
+ /**
+ * How fast is creating a feign instance for each http request, without considering network?
+ */
+ @Benchmark
+ public Response buildAndQuery_fake() {
+ return Feign.builder().client(fakeClient)
+ .target(FeignTestInterface.class, "http://localhost").query();
+ }
+
+ /**
+ * How fast is creating a feign instance for each http request, without considering network, and
+ * without re-parsing the annotated http api?
+ */
+ @Benchmark
+ public Response buildAndQuery_fake_cachedContract() {
+ return Feign.builder().contract(cachedContact).client(fakeClient)
+ .target(FeignTestInterface.class, "http://localhost").query();
+ }
+
+ /**
+ * How fast re-parsing the annotated http api for each http request, without considering network?
+ */
+ @Benchmark
+ public Response buildAndQuery_fake_cachedFeign() {
+ return cachedFakeFeign.newInstance(
+ new HardCodedTarget(FeignTestInterface.class, "http://localhost"))
+ .query();
+ }
+
+ /**
+ * How fast is our advice to use a cached api for each http request, without considering network?
+ */
+ @Benchmark
+ public Response buildAndQuery_fake_cachedApi() {
+ return cachedFakeApi.query();
+ }
+}