Difference between JDK dynamic proxy and CGLib dynamic proxy

  • 2021-06-28 12:32:27
  • OfStack

Case:


public interface ForumService {
 void removeTopic(int topicId);
 void removeForum(int forumId);
}

Performance monitoring of related methods


public class ForumServiceImpl implements ForumService {
 public void removeTopic(int topicId) {
 // PerformanceMonitor.begin("com.hand.proxy.ForumServiceImpl.removeTopic");
 System.out.println(" Simulated Delete Topic Record :" + topicId);
 try {
  Thread.sleep(20);
 } catch (InterruptedException e) {
  e.printStackTrace();
 }
 // PerformanceMonitor.end();
 }
 public void removeForum(int forumId) {
 // PerformanceMonitor.begin("com.hand.proxy.ForumServiceImpl.removeForum");
 System.out.println(" Simulated Delete Forum Record :" + forumId);
 try {
  Thread.sleep(20);
 } catch (InterruptedException e) {
  e.printStackTrace();
 }
 // PerformanceMonitor.end();
 }
}

Performance Monitoring Implementation Class:


public class PerformanceMonitor {
 //  adopt 1 individual ThreadLocal Save performance monitoring information related to the calling thread 
 private static ThreadLocal<MethodPerformance> performanceRecord = new ThreadLocal<MethodPerformance>();
 //  Start with 1 Performance monitoring for target methods 
 public static void begin(String method) {
 System.out.println("begin monitor...");
 MethodPerformance mp = new MethodPerformance(method);
 performanceRecord.set(mp);
 }
 public static void end() {
 System.out.println("end monitor...");
 MethodPerformance mp = performanceRecord.get();
 //  Print out result information for method performance monitoring 
 mp.printPerformance();
 }
}

Used to record performance monitoring information:


public class PerformanceMonitor {
 //  adopt 1 individual ThreadLocal Save performance monitoring information related to the calling thread 
 private static ThreadLocal<MethodPerformance> performanceRecord = new ThreadLocal<MethodPerformance>();
 //  Start with 1 Performance monitoring for target methods 
 public static void begin(String method) {
 System.out.println("begin monitor...");
 MethodPerformance mp = new MethodPerformance(method);
 performanceRecord.set(mp);
 }
 public static void end() {
 System.out.println("end monitor...");
 MethodPerformance mp = performanceRecord.get();
 //  Print out result information for method performance monitoring 
 mp.printPerformance();
 }
}

1. JDK Dynamic Proxy


public class PerformanceMonitor {
 //  adopt 1 individual ThreadLocal Save performance monitoring information related to the calling thread 
 private static ThreadLocal<MethodPerformance> performanceRecord = new ThreadLocal<MethodPerformance>();
 //  Start with 1 Performance monitoring for target methods 
 public static void begin(String method) {
 System.out.println("begin monitor...");
 MethodPerformance mp = new MethodPerformance(method);
 performanceRecord.set(mp);
 }
 public static void end() {
 System.out.println("end monitor...");
 MethodPerformance mp = performanceRecord.get();
 //  Print out result information for method performance monitoring 
 mp.printPerformance();
 }
}

public class ForumServiceTest {
 @Test
 public void proxy() {
 ForumService forumService = new ForumServiceImpl();
 PerformanceHandler handler = new PerformanceHandler(forumService);
 ForumService proxy = (ForumService) Proxy.newProxyInstance(forumService.getClass().getClassLoader(),
  forumService.getClass().getInterfaces(), handler);
 proxy.removeForum(10);
 proxy.removeTopic(1012);
 }
}

The following output information is obtained:

begin monitor...
Simulate deletion of Forum records:10
end monitor...
com.hand.proxy.ForumServiceImpl.removeForum took 21 milliseconds
begin monitor...
Simulate deletion of Topic records: 1012
end monitor...
com.hand.proxy.ForumServiceImpl.removeTopic took 21 milliseconds

2. CGLib Dynamic Proxy


 <!-- https://mvnrepository.com/artifact/cglib/cglib -->
 <dependency>
  <groupId>cglib</groupId>
  <artifactId>cglib</artifactId>
  <version>2.2.2</version>
 </dependency>

public class CglibProxy implements MethodInterceptor {
 private Enhancer enhancer = new Enhancer();
 public Object getProxy(Class clazz) {
 enhancer.setSuperclass(clazz);
 enhancer.setCallback(this);
 return enhancer.create();
 }
 public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
 PerformanceMonitor.begin(obj.getClass().getName() + "." + method.getName());
 Object result = proxy.invokeSuper(obj, args);
 PerformanceMonitor.end();
 return result;
 }
}

public class ForumServiceTest2 {
 @Test
 public void proxy() {
 CglibProxy proxy = new CglibProxy();
 ForumServiceImpl forumService = (ForumServiceImpl) proxy.getProxy(ForumServiceImpl.class);
 forumService.removeForum(10);
 forumService.removeTopic(1023);
 }
}

1), Differences between JDK and CGLib

The JDK dynamic proxy can only generate proxies for classes that implement interfaces, not for classes CGLib implements a proxy for a class, mainly by generating a subclass of the specified class that overrides its methods (inheritance)

2) Basis for Spring to choose JDK or CGLib

When Bean implements the interface, Spring uses JDK's dynamic proxy Spring is implemented using CGLib when Bean does not implement the interface CGLib can be enforced (added to Spring configuration) < aop: aspectj-autoproxy proxy-target-class="true"/ > )

3), Performance comparison between JDK and CGLib

Using CGLib to implement dynamic proxy, the bottom layer of CGLib uses ASM byte code generation framework and byte code technology to generate proxy classes, which is more efficient than using Java before JDK1.6.Only 1 Note that CGLib cannot proxy methods declared as final because CGLib principle is to dynamically generate subclasses of proxied classes. After JDK1.6, JDK1.7, JDK1.8 optimized JDK dynamic proxy step by step, JDK proxy efficiency was higher than CGLib proxy efficiency with fewer calls. Only when a large number of calls were made, JDK1.6 and JDK1.7 were 1 point less efficient than CGLib proxy, but by JDK1.8, JDK proxy efficiency was higher than CGLib proxy.

summary


Related articles: