Definition and Goal
The dynamic proxy can be divided into two parts: “proxy” and “dynamic”——the “proxy(pattern)” is one kind of design pattern in GoF, and the “dynamic” means the proxy pattern can be polished with the help of reflection mechanism in JVM. The ability to decoupling the routine tasks and business tasks is the reason why dynamic proxy is widely used in many Java Web Framework(Like Spring).
Overview
In this article, we will elaborate on the evolution of proxy during the example Database transaction, to illustrate the idea of this magic proxy, and at the end we will demystify the implementation of how this amazing mechanism implemented behind JDK.
Background
The task of own design is modeling how to manipulate the database transaction, we have only one table named User, providing two method: add, delelete for outsider. Pay attention the fact that we need to use start and end routine before and after the normal operation on database to gurantee the atomic of our transaction.
First, we define the interface ingerated with our functions
1 | interface UserService { |
Evolution
Naive
The naive way is to implement the interface of the UserService brutally,
1 | class UserServiceNoProxy implements UserService { |
The shortcoming of this implementation is the mixture the code of routine operation(Start Close DB connection) and the one of the variable operation(Add or Delete user). So our next improvement is to sepearate these two kinds of code.
Static Proxy
We generate two classes to decouple the routine code and the normal code.
UserServiceImpl: Contains the normal functions to manipulate database
1 | class UserServiceImpl implements UserService { |
UserServiceStaticProxy: The wrapper of UserServiceImpl, attached with routine functions
1 | class UserServiceStaticProxy implements UserService { |
By the proxy pattern, we can seperate the operation into two classes. But one thing is still disturbing, let’s say, the addUser and deleteUser both contains the open and close , which are redundant. So we need to introduce the dynamic proxy to sublime.
Dynamic Proxy
Before coding, we have to say that the code below is a little bold to your intuition, and you should just follow the rules to generate the code, we will demysify it in the next part.
We need a few package related to Reflect to create a Dynamic proxy.
1 | import java.lang.reflect.InvocationHandler; |
The key idea is to create a dynamic proxy is by implementing InvocationHandler, then override the getProxy and invoke, in the invoke method we wrap the operation logic with routine
1 | class ServiceProxy implements InvocationHandler{ |
Once we create ServiceProxy class, the next part is to use it to manipulate data, the test code is shown below:
1 | public class TestDynamicProxy { |
The result should be consistent with the static proxy, but with tiny code. In the next part, I will explore the InvocationHandler in the JDK.
Demystify the magic behind the dynamic Proxy
There are not only one way to implement dynamic proxy in java, the way mentioned about is one of them called JDK Dynamic Proxy, we will focus on it in the part below:
JDK Dynamic Proxy
First we need to recap the procedure of create a dynamic Proxy:
a.Use a proxy class A Implements the InvocationHandler with a implemented class C, finish the invoke and getProxy method, we use the newProxyInstance
function to return the real proxy B in getProxy method
b.Instantiaze the proxy B as b
c.Use b as the proxy of C to call function declared in the interface.
By analysis, we can know the fact that proxy class B is generated by the extant code, as for how to create a new class in JVM, we just need to generate the corresponding java file and compile it into binary .class file ,then use the class loader to load the file into corresponding position in JVM memory. We will not talk about the detailed code of it due to the limitation of time.
CGLIB
This is an open-source library to generate the class on low level, which means it skip the copiling time spent in JDK Proxy. We will talk about it later.