JDK动态代理与CGLib动态代理的区别对比

案例:

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

对相关方法进行性能监控

public class ForumServiceImpl implements ForumService {
 public void removeTopic(int topicId) {
 // PerformanceMonitor.begin("com.hand.proxy.ForumServiceImpl.removeTopic");
 System.out.println("模拟删除Topic记录:" + 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("模拟删除Forum记录:" + forumId);
 try {
  Thread.sleep(20);
 } catch (InterruptedException e) {
  e.printStackTrace();
 }
 // PerformanceMonitor.end();
 }
}

性能监控实现类:

public class PerformanceMonitor {
 // 通过一个ThreadLocal保存与调用线程相关的性能监视信息
 private static ThreadLocal<MethodPerformance> performanceRecord = new ThreadLocal<MethodPerformance>();
 // 启动对某一目标方法的性能监视
 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();
 // 打印出方法性能监视的结果信息
 mp.printPerformance();
 }
}

用于记录性能监控信息:

public class PerformanceMonitor {
 // 通过一个ThreadLocal保存与调用线程相关的性能监视信息
 private static ThreadLocal<MethodPerformance> performanceRecord = new ThreadLocal<MethodPerformance>();
 // 启动对某一目标方法的性能监视
 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();
 // 打印出方法性能监视的结果信息
 mp.printPerformance();
 }
}

1、JDK动态代理

public class PerformanceMonitor {
 // 通过一个ThreadLocal保存与调用线程相关的性能监视信息
 private static ThreadLocal<MethodPerformance> performanceRecord = new ThreadLocal<MethodPerformance>();
 // 启动对某一目标方法的性能监视
 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();
 // 打印出方法性能监视的结果信息
 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);
 }
}

得到以下输出信息:

begin monitor...
模拟删除Forum记录:10
end monitor...
com.hand.proxy.ForumServiceImpl.removeForum花费21毫秒
begin monitor...
模拟删除Topic记录:1012
end monitor...
com.hand.proxy.ForumServiceImpl.removeTopic花费21毫秒

2、CGLib动态代理

 <!-- 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)、JDK和CGLib的区别

  • JDK动态代理只能对实现了接口的类生成代理,而不能针对类
  • CGLib是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法(继承)

2)、Spring在选择用JDK还是CGLib的依据

  • 当Bean实现接口时,Spring就会用JDK的动态代理
  • 当Bean没有实现接口时,Spring使用CGLib来实现
  • 可以强制使用CGLib(在Spring配置中加入<aop:aspectj-autoproxy proxy-target-class=“true”/>)

3)、JDK和CGLib的性能对比

  • 使用CGLib实现动态代理,CGLib底层采用ASM字节码生成框架,使用字节码技术生成代理类,在JDK1.6之前比使用Java反射效率要高。唯一需要注意的是,CGLib不能对声明为final的方法进行代理,因为CGLib原理是动态生成被代理类的子类。
  • 在JDK1.6、JDK1.7、JDK1.8逐步对JDK动态代理优化之后,在调用次数较少的情况下,JDK代理效率高于CGLib代理效率,只有当进行大量调用的时候,JDK1.6和JDK1.7比CGLib代理效率低一点,但是到JDK1.8的时候,JDK代理效率高于CGLib代理

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对我们的支持。如果你想了解更多相关内容请查看下面相关链接

(0)

相关推荐

  • Spring AOP中的JDK和CGLib动态代理哪个效率更高?

    一.背景 今天有小伙伴面试的时候被问到:Spring AOP中JDK 和 CGLib动态代理哪个效率更高? 二.基本概念 首先,我们知道Spring AOP的底层实现有两种方式:一种是JDK动态代理,另一种是CGLib的方式. 自Java 1.3以后,Java提供了动态代理技术,允许开发者在运行期创建接口的代理实例,后来这项技术被用到了Spring的很多地方. JDK动态代理主要涉及java.lang.reflect包下边的两个类:Proxy和InvocationHandler.其中,Invoc

  • Spring AOP注解失效的坑及JDK动态代理

    @Transactional @Async等注解不起作用 之前很多人在使用Spring中的@Transactional, @Async等注解时,都多少碰到过注解不起作用的情况. 为什么会出现这些情况呢?因为这些注解的功能实际上都是Spring AOP实现的,而其实现原理是通过代理实现的. JDK动态代理 以一个简单的例子理解一下JDK动态代理的基本原理: //目标类接口 public interface JDKProxyTestService { void run(); } //目标类 publ

  • 深入理解java动态代理的两种实现方式(JDK/Cglib)

    什么是代理模式? 代理模式:在调用处不直接调用目标类进行操作,而是调用代理类,然后通过代理类来调用目标类进行操作.在代理类调用目标类的前后可以添加一些预处理和后处理操作来完成一些不属于目标类的功能. 为什么要使用代理模式? 通过代理模式可以实现对目标类调用的控制.在目标类调用前/后进行一些不属于目标类的操作,如:数据验证.预处理.后处理.异常处理等 什么是静态代理什么是动态代理? 静态代理:代理类只能实现对"特定接口的实现类"进行代理 动态代理:代理类可以实现对多种类的代理 jdk代理

  • jdk动态代理源码分析过程

    代理对象的生成方法是: Proxy.newProxyInstance(...) ,进入这个方法内部,一步一步往下走会发现会调用 ProxyGenerator.generateProxyClass() ,这个方法用来生成代理类的字节码. 下面通过调用 ProxyGenerator.generateProxyClass()方法在本地生成代理类. 1.首先要有一个接口 2.生成代理类的方法如下 3.将生成的代理类导入到idea中查看是长这样 // // Source code recreated fr

  • 详解Spring的两种代理方式:JDK动态代理和CGLIB动态代理

    代理模式 代理模式的英文叫做Proxy或Surrogate,中文都可译为"代理",所谓代理,就是一个人或者一个机构代表另一个人或者另一个机构采取行动.在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用 A. 抽象主题角色 声明了真实主题和代理主题的共同接口,这样一来在任何可以使用真实主题的地方都可以是使用代理主题 B. 代理主题(Proxy)角色: 代理主题角色内部含有对真实主题的引用,从而可以在任何时候操作真实主题对象:代理主题角

  • jdk中动态代理异常处理分析:UndeclaredThrowableException

    背景 在RPC接口调用场景或者使用动态代理的场景中,偶尔会出现UndeclaredThrowableException,又或者在使用反射的场景中,出现InvocationTargetException,这都与我们所期望的异常不一致,且将真实的异常信息隐藏在更深一层的堆栈中.本文将重点分析下UndeclaredThrowableException 先给结论 使用jdk动态代理接口时,若方法执行过程中抛出了受检异常但方法签名又没有声明该异常时则会被代理类包装成UndeclaredThrowableE

  • 浅谈Java代理(jdk静态代理、动态代理和cglib动态代理)

    一.代理是Java常用的设计模式,代理类通过调用被代理类的相关方法,并对相关方法进行增强.加入一些非业务性代码,比如事务.日志.报警发邮件等操作. 二.jdk静态代理 1.业务接口 /** * 业务接口 * @author pc * */ public interface UserService { // 增加一个用户 public void addUser(); // 编辑账户 public void editUser(); } 2.业务实现类 /** * 业务实现类 * @author pc

  • java动态代理和cglib动态代理示例分享

    java动态代理类可以分为两种. 静态代理:由程序员创建或特定工具自动生成源代码,再对其编译.在程序运行前,代理类的.class文件就已经存在了. 动态代理:在程序运行时,运用反射机制动态创建而成. 一.首先我们进行java动态代理的演示. 现在我们有一个简单的业务接口Saying,如下: 复制代码 代码如下: package testAOP;public interface Saying {public void sayHello(String name);    public void ta

  • JAVA中的静态代理、动态代理以及CGLIB动态代理总结

    代理模式是java中最常用的设计模式之一,尤其是在spring框架中广泛应用.对于java的代理模式,一般可分为:静态代理.动态代理.以及CGLIB实现动态代理. 对于上述三种代理模式,分别进行说明. 1.静态代理 静态代理其实就是在程序运行之前,提前写好被代理方法的代理类,编译后运行.在程序运行之前,class已经存在. 下面我们实现一个静态代理demo: 静态代理 定义一个接口Target package com.test.proxy; public interface Target { p

  • Spring学习之动态代理(JDK动态代理和CGLIB动态代理)

    前言 动态代理,是一种通过运行时操作字节码,以达到增强类的功能的技术,也是Spring AOP操作的基础,关于AOP的内容,将在后面的笔记中详细讲解,本小节主要是理清楚动态代理,毕竟,Spring的AOP是基于动态代理技术,对动态代理技术有所了解,对于学习Spring AOP也会有帮助 动态代理技术详解 动态代理,现在主要是用于增强类的功能,同时由于是具有动态性,所以避免了需要频繁创建类的操作,同时,也使得原有的代码在不需要改变的情况下,对类的功能进行增强,主要的动态代理技术有:通过实现目标接口

  • JDK动态代理与CGLib动态代理的区别对比

    案例: public interface ForumService { void removeTopic(int topicId); void removeForum(int forumId); } 对相关方法进行性能监控 public class ForumServiceImpl implements ForumService { public void removeTopic(int topicId) { // PerformanceMonitor.begin("com.hand.proxy

  • jdk动态代理和cglib动态代理详解

    目录 静态代理 基于继承的方式实现静态代理 基于聚合的方式实现静态代理 继承与聚合方式实现的静态代理对比 动态代理 JDK动态代理 如何实现一个HashMap的动态代理类? Cglib动态代理 JDK与Cglib动态代理对比? 动态代理和静态代理的区别? Spring如何选择两种代理模式的? 总结 如上图,代理模式可分为动态代理和静态代理,我们比较常用的有动态代理中的jdk动态代理和Cglib代理,像spring框架.hibernate框架中都采用了JDK动态代理,下面将结合代码阐述两种代理模式

  • Java使用JDK与Cglib动态代理技术统一管理日志记录

    Java中动态代理主要有JDK和CGLIB两种方式. 区别主要是jdk是代理接口,而cglib是代理类. 优点:这种方式已经解决我们前面所有日记需要的问题.非常的灵活.而且可以方便的在后期进行维护和升级. 缺点:当然使用jdk动态代理,必需要有接口.如果没有接口.就无法使用jdk动态代理技术. 计算接口 Calculate.java public interface Calculate { /** * 加法运算 * @param num1 参数 1 * @param num2 参数 2 * @r

  • JDK动态代理之ProxyGenerator生成代理类的字节码文件解析

    通过前面几篇的分析,我们知道代理类是通过Proxy类的ProxyClassFactory工厂生成的,这个工厂类会去调用ProxyGenerator类的generateProxyClass()方法来生成代理类的字节码.ProxyGenerator这个类存放在sun.misc包下,我们可以通过OpenJDK源码来找到这个类,该类的generateProxyClass()静态方法的核心内容就是去调用generateClassFile()实例方法来生成Class文件.我们直接来看generateClas

随机推荐