Implementation principle of Spring AOP -- dynamic proxy

The bottom layer of Spring AOP is realized through dynamic proxy, including JDK dynamic proxy and cglib dynamic proxy.

JDK dynamic agent

Handwritten JDK dynamic proxy

public interface UserInterface {
    Integer test();
}

Proxy class

public class User implements UserInterface {

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    private String name;

    @Override
    public Integer test() {
        return Integer.valueOf(name);
    }
}

proxy class

public class JDKProxy implements InvocationHandler {

    private Object target;

    public JDKProxy(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("-----before-----" + method.getName());
        Object result = method.invoke(target, args);
        System.out.println("-----after-----" + result);
        return result;
    }
}

Test class

public class ProxyTest {
    public static void main(String[] args) {
        User user = new User();
        user.setName("123");
        UserInterface proxyInstance = (UserInterface) Proxy.newProxyInstance(User.class.getClassLoader(), User.class.getInterfaces(), new JDKProxy(user));
        proxyInstance.test();
    }
}

The output result is:

-----before-----test

123

-----after-----123

It may also be implemented through anonymous inner classes, as follows

public static void main(String[] args) {
    User user = new User();
    user.setName("123");
    UserInterface proxyInstance = (UserInterface) Proxy.newProxyInstance(user.getClass().getClassLoader(), user.getClass().getInterfaces(), new InvocationHandler() {
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("----before----" + method.getName());
            Object result = method.invoke(user, args);
            System.out.println("----after----" + result);
            return result;
        }
    });
    proxyInstance.test();
}

The output results and are the same as above:

----before----test

123

----after----123

cglib dynamic proxy

Handwritten cglib dynamic proxy

Proxy class

public class User {
    void test() {
        System.out.println("test");
    }
}

proxy class

public class UserCglibProxy implements MethodInterceptor {
    @Override
    public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("---before---" + method.getName());
        Object result = methodProxy.invokeSuper(o, args);
        System.out.println("---after---" + result);
        return result;
    }
}

Test class

public class CglibTest {
    public static void main(String[] args) {
        UserCglibProxy cglibProxy = new UserCglibProxy();
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(User.class);
        enhancer.setCallback(cglibProxy);
        User userTest = (User) enhancer.create();
        userTest.test();
    }
}

The output result is:

---before---test

test

---after---null

Differences between JDK dynamic agent and cglib dynamic agent

Different writing methods

According to the above code, it can be seen that:

JDK dynamic proxy needs to implement InvocationHandler interface and override invoke method.

cglib dynamic proxy needs to implement the MethodInterceptor interface, rewrite the intercept method, and set the proxy class and proxy class through Enhancer.

Different implementation principles

The JDK dynamic proxy uses the interceptor (the interceptor must implement InvocationHandler) plus the reflection mechanism to generate an anonymous class to implement the proxy interface. It calls InvocationHandler before calling the specific method, so the Jdk dynamic proxy must be based on the interface into the action agent, and the dynamic proxy class is implemented by the generated agent.

cglib dynamic proxy is implemented by using ASM technology to load the proxy class file and modify the bytecode to generate subclasses. Therefore, it is impossible to dynamically proxy the method of final modification.

Different efficiency

With the JDK version upgrade, the JDK dynamic agent has been optimized. Before JDK 1.6, the efficiency of JDK dynamic agent was lower than that of cglib dynamic agent. JDK in versions 1.6 and 1.7, the efficiency of JDK dynamic agent is higher than that of cglib dynamic agent. Only when a large number of calls are made, the efficiency of JDK dynamic agent is a little lower than that of cglib dynamic agent. JDK 1.8 and later JDK dynamic agents are more efficient than cglib dynamic agents.

Which does spring AOP use?

JDK dynamic proxy is used by default. cglib dynamic proxy is used when the interface is not implemented.

Tags: Java Spring AOP

Posted on Wed, 08 Sep 2021 03:52:06 -0400 by The Stranger