JDK dynamic proxy and bytecode enhancement CGLIB

A, JDK dynamic proxies

Java.lang.reflect package in Java has its own proxy support, the class (Proxy.java) for dynamically generated proxy class, you need only transfer target interface, and a class loader InvocationHandler target interface can be generated for the target interface proxy class and proxy object. We call this Java technology: Dynamic Proxy

@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,
                                      Class<?>[] interfaces,
                                      InvocationHandler h)
    throws IllegalArgumentException
{
//...
}

In Java provisions, in order to generate a proxy for an object, the object must have an interface, so the interfaces must be an interface.

In the dynamic agent technology, due no matter what method the user invokes the proxy object, call invoke methods are developer-written InvocationHandler of (this corresponds to invoke methods to intercept the proxy object method call).

Therefore JDK dynamic proxy for the overall process:

  1. Achieve InvocationHandler, after the processing logic used to intercept the object. (The object must be an interface, the interface or superclass)
  2. Use Proxy.newProxyInstance generated proxy object.

The following is a specific example of an implementation of the AOP JDK dynamic code:

1. The target (the Target) class

public interface UserService {
    void eat();
}
public class UserServiceImpl implements UserService {
    @Override
    public void eat() {
        System.out.println("吃东西");
    }
}

2. section (Aspect) class

public class MyAspect {
    /**
     * 前置通知
     */
    public void before() {
        System.out.print("先洗手再");
    }
}

3. weaving (Weaving) Process

/**
 * 产生代理对象的工厂类
 */
public class MyFactoryBean {

    private MyFactoryBean() {
    }
    
    public static UserService getInstance() {
        // target : 目标类
        final UserService userService = new UserServiceImpl();
        // Aspect : 切面类
        final MyAspect myAspect = new MyAspect();
        // Weaving : 织入,也就是产生代理的过程
        UserService proxyInstance = (UserService) Proxy.newProxyInstance(UserService.class.getClassLoader(),
                new Class[]{UserService.class}, (Object proxy, Method method, Object[] args) -> {
                    // 模拟切点 - pointcut
                    if ("eat".equals(method.getName())) {
                        myAspect.before();
                    }
                    return method.invoke(userService, args);
                });
        return proxyInstance;
    }
}
    public static void main(String[] args) {
        UserService userService = MyFactoryBean.getInstance();
        // 先洗手再吃东西
        userService.eat();
    }

Think about it, this is actually with the AOP we normally use a very similar, Spring inside a pre-defined notification (@Before), exception notification (@AfterThrowing) and so on, Spring is just replaced by screening these annotations to choose when call notification method, additionally, Spring further entry points and select the target class by cutting point expression.

Two, CGLIB dynamic proxies

CGLIB dynamic proxy requires the introduction of third-party libraries, call intercept way to achieve a subclass of it generated by modifying the proxy object, the proxy object does not need to implement the interface, but the agent class can not be final, proxy methods can not be final.

/**
 * 产生代理对象的工厂类
 */
public class MyFactoryBean {

    private MyFactoryBean() {
    }

    public static UserService getInstance() {
        // target : 目标类
        final UserService userService = new UserServiceImpl();
        // Aspect : 切面类
        final MyAspect myAspect = new MyAspect();
        // Weaving : 织入,也就是产生代理的过程
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(userService.getClass());
        enhancer.setUseCache(false);
        enhancer.setCallback(new MethodInterceptor() {
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                // 模拟 pointcut-切点
                if ("eat".equals(method.getName())) {
                    myAspect.before();
                }
                return methodProxy.invokeSuper(o, objects);
            }
        });
        return (UserService) enhancer.create();
    }

    public static void main(String[] args) {
        UserService proxyInstance = MyFactoryBean.getInstance();
        // 先洗手再吃东西
        proxyInstance.eat();
    }
}

Third, the summary

When the dynamic agent in the JDK, requires proxy class must be an interface or class inheritance interface, because JDK finally generated proxy class is actually realized the proxy class by agents of the interface and inherits the Proxy class (inherited Proxy class java is to determine whether the proxy class class method), to find the reflection by an interface, implemented invoke method call interception InvocationHandler.

CGLIB bytecode enhancement is a good supplement JDK dynamic proxy, CGLIB last generated proxy class is a class that inherits proxy agent class, the agent is achieved by overwriting non-final process in the proxy class.

Summarized as:

  • JDK dynamic proxy: proxy class must be an interface or class inheritance interface.
  • CGLIB bytecode enhancement: agent class can not final, the agent is not the method of final (inherent limitations).

What about the use of proxy means in a Spring AOP, we do not impose restrictions, it will be based on whether there is a class interface to be treated differently:

  1. When a class has an interface, it will choose the JDK dynamic proxy.
  2. When a class does not implement the interface, it will choose CGLIB proxy.

Guess you like

Origin www.cnblogs.com/jmcui/p/11968698.html