A brief analysis of Java implementation dynamic proxy method

  • 2020-04-01 03:27:06
  • OfStack

In some Java projects, MapperScannerConfigurer is used in the integration of mybatis and spring. This class automatically generates dynamic proxy classes based on interface through reverse proxy.

With this in mind, this article has analyzed Java's dynamic proxy.

This article USES a dynamic proxy to simulate interceptors that process transactions.

Interface:


public interface UserService {
  public void addUser();
  public void removeUser();
  public void searchUser();
}

Implementation class:


public class UserServiceImpl implements UserService {
  public void addUser() {
    System.out.println("add user");
  }
  public void removeUser() {
    System.out.println("remove user");
  }
  public void searchUser() {
    System.out.println("search user");
  }
}

Java dynamic proxy can be implemented in two ways

1. Dynamic proxy with JDK

Using the JDK's native dynamic Proxy requires an understanding of the InvocationHandler interface and the Proxy class, both of which are in the java.lang.reflect package.

InvocationHandler is introduced:

The InvocationHandler is the interface implemented by the InvocationHandler of the proxy instance.

Each proxy instance has an associated InvocationHandler. When a method is called on a proxy instance, the method calls the invoke method of the InvocationHandler.

The Proxy is introduced:

Proxy provides static methods for creating dynamic Proxy classes and instances.

Example (simulating an AOP transaction) :


public class TransactionInterceptor implements InvocationHandler {

  private Object target;

  public void setTarget(Object target) {
    this.target = target;
  }
  
  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    System.out.println("start Transaction");
    method.invoke(target, args);
    System.out.println("end Transaction");
    return null;
  }

}

Test code:


public class TestDynamicProxy {

  @Test
  public void testJDK() {
    TransactionInterceptor transactionInterceptor = new TransactionInterceptor();
    UserService userService = new UserServiceImpl();
    transactionInterceptor.setTarget(userService);
    UserService userServiceProxy =
        (UserService) Proxy.newProxyInstance(
            userService.getClass().getClassLoader(),
            userService.getClass().getInterfaces(),
            transactionInterceptor);
    userServiceProxy.addUser();
  }

}

Test results:


start Transaction
add user
end Transaction

Obviously, when we make a method call through the proxy class userServiceProxy, we open and close the transaction before and after the method call.

2. Third party library cglib

CGLIB is a powerful, high-performance, high-quality code generation library for extending Java classes and implementing Java interfaces at runtime.

The biggest difference between it and the JDK's dynamic proxy is that:

JDK dynamic proxy is for interfaces, while cglib is for classes to implement the proxy. Cglib's principle is to generate a subclass of the specified target class and override the method implementation enhancement, but because inheritance is adopted, classes with final modification cannot be proxy.

Example code is as follows:


public class UserServiceCallBack implements MethodInterceptor {

  @Override
  public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
    System.out.println("start Transaction by cglib");
    methodProxy.invokeSuper(o, args);
    System.out.println("end Transaction by cglib");
    return null;
  }

}

Test code:


public class TestDynamicProxy {

  @Test
  public void testCGLIB() {
    Enhancer enhancer = new Enhancer();
    enhancer.setSuperclass(UserServiceImpl.class);
    enhancer.setCallback(new UserServiceCallBack());
    UserServiceImpl proxy = (UserServiceImpl)enhancer.create();
    proxy.addUser();
  }

}

Test results:


start Transaction by cglib
add user
end Transaction by cglib

Interested readers can actually test this article's example, I believe it will be a great gain.


Related articles: