JDK dynamic agent and CGLIB dynamic agent are really different

Absrtact: This article takes you to understand JDK dynamic agent and CGLIB dynamic agent

This article is shared from Huawei cloud community< This article takes you to understand JDK dynamic agent and CGLIB dynamic agent >, author: skin shrimp.

What's the difference between the two

1, Jdk dynamic proxy: use the interceptor (to implement InvocationHandler interface) and add the reflection mechanism to generate an anonymous class of the proxy interface, and call InvokeHandler before calling the specific method.

2,   Cglib dynamic proxy: use ASM framework to load the class file generated by proxy object class, and generate subclasses by modifying its bytecode to proxy

So:

  • If you want to implement JDK dynamic proxy, the proxy class must implement the interface, otherwise it cannot be used;
  • If you want to use CGlib dynamic proxy, the proxy class cannot use final to modify classes and methods;

Also: after jdk6, jdk7 and jdk8 gradually optimize the JDK dynamic agent, the JDK agent efficiency is higher than the CGLIB agent efficiency when the number of calls is small. Only when a large number of calls are made, the jdk6 and jdk7 are a little lower than the CGLIB agent efficiency, but when jdk8, the JDK agent efficiency is higher than the CGLIB agent efficiency.

How

JDK dynamic agent

UserService interface

public interface UserService {

    void addUser();

    void updateUser(String str);

}

UserServiceImpl implementation class

public class UserServiceImpl implements UserService {
    @Override
    public void addUser() {
        System.out.println("Add user");
    }

    @Override
    public void updateUser(String str) {
        System.out.println("Update user information" + str);
    }
}

The UserProxy proxy class implements the InvocationHandler interface and overrides the invoke method

public class UserProxy implements InvocationHandler {
    private Object target;

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

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        Object res = method.invoke(target, args);

        System.out.println("Log");

        return res;
    }
}

Test test class

public class test {
    public static void main(String[] args) {

        UserServiceImpl impl = new UserServiceImpl();
        UserProxy userProxy = new UserProxy(impl);
        UserService userService = (UserService) Proxy.newProxyInstance(impl.getClass().getClassLoader(),impl.getClass().getInterfaces(),userProxy);
        userService.addUser();
        userService.updateUser(": I'm Pipi shrimp");
    }

}

It can be seen that the enhancement is realized and the log is printed out

CGlib dynamic proxy

CGlib is not like JDK dynamic proxy. CGlib needs to import Jar package, so I use SpringBoot to import dependencies directly

<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.3.0</version>
</dependency>

UserServiceImpl proxy class

public class UserServiceImpl {

    public void addUser() {
        System.out.println("Added a user");
    }

    public void deleteUser() {
        System.out.println("A user was deleted");
    }

}

UserServiceCGlib proxy

public class UserServiceCGlib implements MethodInterceptor {
    private Object target;

    public UserServiceCGlib() {
    }

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

    //Returns a proxy object: the proxy object of the target object
    public Object getProxyInstance() {
        //1. Create a tool class
        Enhancer enhancer = new Enhancer();
        //2. Set parent class
        enhancer.setSuperclass(target.getClass());
        //3. Set callback function
        enhancer.setCallback(this);
        //4. Create a subclass object, that is, a proxy object
        return enhancer.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("Enhancement start~~~");
        Object result = methodProxy.invokeSuper(o, objects);
        System.out.println("Enhancement end~~~");
        return result;
    }

}

Test test class

public class test {

    public static void main(String[] args) {
        UserServiceCGlib serviceCGlib = new UserServiceCGlib(new UserServiceImpl());
        UserServiceImpl userService = (UserServiceImpl)serviceCGlib.getProxyInstance();
        userService.addUser();
        System.out.println();
        userService.deleteUser();
    }

}

It can be seen that the enhancement is realized and the log is printed out

Usage scenario

Here, I believe you have basically mastered the difference and implementation between JDK dynamic agent and CGlib dynamic agent

However, in the interview process, in addition to answering the above points, you should also answer their use scenarios, which is actually the bonus of the interview

So, what are the usage scenarios of these two dynamic agents???

Answer: Spring AOP

The following is how Spring AOP creates a proxy

@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {

   if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
      Class<?> targetClass = config.getTargetClass();
      if (targetClass == null) {
         throw new AopConfigException("TargetSource cannot determine target class: " +
               "Either an interface or a target is required for proxy creation.");
      }
      //If
      if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
         return new JdkDynamicAopProxy(config);
      }
      return new ObjenesisCglibAopProxy(config);
   }
   else {
      return new JdkDynamicAopProxy(config);
   }
}

1. If the target object implements the interface, the dynamic proxy of JDK will be adopted by default
2. CGLIB can also be enforced if the target object implements an interface
3. If the target object does not implement the interface, the CGLIB library must be used, and spring will automatically convert between JDK dynamic agent and CGLIB

If you need to force CGLIB to implement AOP, you need to configure spring. AOP. Proxy target class = true or @ EnableAspectJAutoProxy(proxyTargetClass = true

 

Click focus to learn about Huawei cloud's new technologies for the first time~

Tags: JDK Spring Interview cglib

Posted on Thu, 02 Dec 2021 20:40:48 -0500 by jamesm87