[Spring Boot] Feign Client and JDK Dynamic Proxy

While I was reading Head First Design Patterns book, I came across Proxy pattern. Then, I ran into a brief introduction to Invocation Handler in Java. I remembered a conversation almost 3 years ago with a friend of mine that I worked with before via Pivotal App-Tx engagement (now a colleague actually!) who taught me the basics of Spring Cloud and who encouraged me to become an open-source contributor.

Li Gang: “Do you know how Feign Client works with just interface?”

Me: “Nope..”

Li Gang: “It works due to JDK proxy and invocation handler.”

Me: ‘ㅇ_ㅇ … ? ’

My discovery stopped back then but here I am today to learn about JDK Proxy. A lot of blogs talk about JDK Proxy with Spring AOP. In this article, let’s see how Feign Client makes use of JDK Proxy.

Basics of JDK Dynamic Proxy

Proxy can be created with an implementation of InvocationHandler.

Let’s look at an example to see how it works during runtime. In this example, invocation handler checks the method name and prints accordingly. Then method.invoke(target, args) invokes the methods on the concrete class. This indicates that pre-processing or post-processing can be added inside InvocationHandler.

The result looks like the screenshot below.

output console

Back to Feign Client

Whenever I come across a requirement where I need to invoke APIs provided by other services, I have a tendency of using Feign Client. I find it very convenient because

  • It is declarative and it follows similar structure to Spring MVC annotations
  • No work needed with connections or input/output streams
  • Integrates well with other Spring Cloud components out-of-box

Implementation

So here is a client that gets product information from a fake REST API server.

Of course, I will create an endpoint that makes use of our client.

Questions

Here are some questions that I needed answers to.

  • How is proxy created?
  • How can it run without an implementation? Feign Client is an interface and there is no concrete class for it in our code.
  • How can it make HTTP calls just by defining an interface? I know that Feign Client by default uses HttpURLConnection but how?

Q1. How is proxy created?

From our controller, it can be observed that ProductClient is a proxy. It is a proxy to HardCodedTarget which implements Target. But what makes it a proxy?

So when the application starts up, FeignClientRegistrar will basically scan Feign Clients annotations in our code to create BeanDefinitions to the BeanFactory.

FeignClientsRegistrar.java

Then when creating a bean, calling factoryBean.getObject() will return a Feign client created with the specified data and the context information.

FeignClientsRegistrar.java

Which will lead to

Feign.java

build() builds a factory

Feign.java

This is the place where proxy is created using Proxy.newProxyInstance(). It is interesting that InvocationHandler is created with methodToHandler map. This map contains key as ProductClient.fetchProduct(int) and value of SynchronousMethodHandler. This SynchronousMethodHandler will later create and send HTTP request. This is basically the key mapping that translates our client.fetchProduct(id) method to a HTTP call.

ReflectiveFeign.java
Factory in SynchronousMethodHandler.java

Q2. How can it run without an implementation?

From what we have observed up to this point, it is clear that FeignClientsRegistrar registers required beans. For FeignClientsRegistrar to be imported, the application needs to declare @EnableFeignClients annotation.

Q3. How can it make HTTP calls just by defining an interface?

From this point on, breakpoints take place after client.fetchProduct(id).

We talked about methodToHandler map earlier when creating an invocation handler. FeignInvocationHandler is the invocation handler we created earlier. I mentioned that the dispatch map in the below code (same as methodToHandler map) returns value of SynchronousMethodHandler. This will result returning the result of SynchronousMethodHandler::invoke.

FeignInvocationHandler in ReflectiveFeign.java

The invoke method will trigger executeAndDecode().

SynchronousMethodHandler.java

Which then will trigger client.execute().

SynchronousMethodHandler.java

Lastly, here is the code where HttpURLConnection is created to send request and return response.

Default in Client.java

Summary

In this article, we saw a real life example of a Proxy pattern in one of my favorite libraries.

This article also covered:

  • Basic example of JDK dynamic proxy
  • How proxy is used in Feign Client

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store