我们先看一下下面这段代码:

可以看到,这里为了增加事务,对业务代码的侵入性较强,不利于后期的维护,那么有没有办法使业务代码和事务代码分开呢?答案肯定是有的,在Spring中可以使用AOP进行解耦,但是其底层其实是使用的动态代理实现的,那么我们在这里就介绍一下两种常见的动态代理模式:JDK动态代理CGLIB动态代理

常用的动态代理技术
JDK 代理 : 基于接口的动态代理技术·:利用拦截器(必须实现InvocationHandler)加上反射机制生成
一个代理接口的匿名类,再调用具体方法前调用InvokeHandler来处理,从而实现方法增强

CGLIB 代理 : 基于父类的动态代理技术:动态生成一个要代理的子类,子类重写要代理的类的所有不是
final的方法。在子类中采用方法拦截技术拦截所有的父类方法的调用,顺势织入横切逻辑,对方法进行
增强

如上图,目标对象(目标类)就是被代理的对象,

  • JDK动态代理:代理类是去实现目标类的接口(目标类必须实现接口),和目标类同级

  • CGLIB动态代理:代理类是采用ASM生成目标类的子类,和目标类是继承关系

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

性能比较:
在jdk6、jdk7、jdk8逐步对JDK动态代理优化之后,在调用次数较少的情况下,JDK代理效率高于CGLIB代理效率,只有当进行大量调用的时候,jdk6和jdk7比CGLIB代理效率低一点

实现方式:

JDK代理是不需要依赖第三方的库,只要JDK环境就可以进行代理,需要满足以下要求:
 1. 实现InvocationHandler接口,重写invoke()
 2. 使用 Proxy.newProxyInstance() 产生代理对象
 3. 被代理的对象必须要实现接口

CGLib 必须依赖于CGLib的类库,需要满足以下要求:
 1. 实现MethodInterceptor接口,重写intercept()
 2. 使用 Enhancer对象.create() 产生代理对象
 3. 被代理的对象不能使用final修饰

一、JDK动态代理方式

Jdk工厂类

/*JDK动态代理工厂类*/
@Component
public class JDKProxyFactory {@Autowiredprivate AccountService accountService;@Autowiredprivate TransactionManager transactionManager;/*采用JDK动态代理技术来生成目标类的代理对象ClassLoader loader, : 类加载器:借助被代理对象获取到类加载器Class<?>[] interfaces, : 被代理类所需要实现的全部接口InvocationHandler h : 当代理对象调用接口中的任意方法时,那么都会执行InvocationHandler中invoke方法*/public AccountService createAccountSericeJDKProxy(){AccountService accountServiceProxy= (AccountService) Proxy.newProxyInstance(accountService.getClass().getClassLoader(), accountService.getClass().getInterfaces(), new InvocationHandler() {@Override      //   proxy: 当前的代理对象引用   method:被调用的目标方法的引用   //   args:被调用的目标方法所用到的参数public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {try {if(method.getName().equals("transfer")) {System.out.println("进行了前置增强");// 手动开启事务:调用事务管理器类中的开启事务方法transactionManager.beginTransaction();// 让被代理对象的原方法执行method.invoke(accountService, args);System.out.println("进行了后置增强");// 手动提交事务transactionManager.commit();}else {method.invoke(accountService, args);}} catch (Exception e) {e.printStackTrace();// 手动回滚事务transactionManager.rollback();} finally {// 手动释放资源transactionManager.release();}return null;}});return  accountServiceProxy;}
}


这里, method.invoke(accountService, args) 进行业务方法的调用,然后在前后增加了事务的处理

测试代码:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"classpath:applicationContext.xml"})
public class AccountServiceImplTest {@Autowiredprivate JDKProxyFactory proxyFactory;/*测试JDK动态代理优化转账案例*/@Testpublic void testTransferProxyJDK(){// 当前返回的实际上是AccountService的代理对象proxyAccountService accountSericeJDKProxy = proxyFactory.createAccountSericeJDKProxy();// 代理对象proxy调用接口中的任意方法时,都会执行底层的invoke方法accountSericeJDKProxy.transfer("tom","jerry",100d);accountSericeJDKProxy.save();}
}

二、CGLIB动态代理方式

Cglib工厂类

/*该类就是采用cglib动态代理来对目标类(AccountServiceImpl)进行方法(transfer)的动态增强(添加上事务控制)*/
@Component
public class CglibProxyFactory {@Autowiredprivate AccountService accountService;@Autowiredprivate TransactionManager transactionManager;public AccountService createAccountServiceCglibProxy(){// 编写cglib对应的API来生成代理对象进行返回// 参数1 : 目标类的字节码对象// 参数2:  动作类,当代理对象调用目标对象中原方法时,那么会执行intercept方法AccountService accountServiceproxy = (AccountService) Enhancer.create(accountService.getClass(), new MethodInterceptor() {// o : 代表生成的代理对象   method:调用目标方法的引用  // objects:方法入参    methodProxy:代理方法@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {try {// 手动开启事务:调用事务管理器类中的开启事务方法transactionManager.beginTransaction();method.invoke(accountService, objects);transactionManager.commit();} catch (Exception e) {e.printStackTrace();// 手动回滚事务transactionManager.rollback();} finally {// 手动释放资源transactionManager.release();}return null;}});return accountServiceproxy;}
}

这里, method.invoke(accountService, objects) 进行业务方法的调用,然后在前后增加了事务的处理

测试代码

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"classpath:applicationContext.xml"})
public class AccountServiceImplTest {@Autowired private CglibProxyFactory cglibProxyFactory;/*测试Cglib动态代理优化转账案例*/@Testpublic void testTransferProxyCglib(){// accountServiceCglibProxy: proxyAccountService accountServiceCglibProxy = cglibProxyFactory.createAccountServiceCglibProxy();accountServiceCglibProxy.transfer("tom","jerry",100d);}
}

JDK动态代理和CGLIB动态代理介绍相关推荐

  1. Spring AOP之---基于JDK动态代理和CGLib动态代理的AOP实现

    AOP(面向切面编程)是OOP的有益补充,它只适合那些具有横切逻辑的应用场合,如性能监测,访问控制,事物管理,日志记录等.至于怎么理解横切逻辑,敲完实例代码也就明白了. 为什么要使用AOP,举个栗子: ...

  2. Java中动态代理的两种方式JDK动态代理和cglib动态代理以及区别

    视频功能审核通过了,可以看视频啦!记得点关注啊~ 注意:因为网络原因,视频前一两分钟可能会比较模糊,过一会儿就好了 记得点关注啊,视频里的wx二维码失效了,wx搜索:"聊5毛钱的java&q ...

  3. 什么是代理模式?代理模式有什么用?通过一个小程序分析静态代理和动态代理。自己简单实现动态代理。JDK动态代理和CGLIB动态代理的区别。

    1. 代理模式有什么用 ①功能增强,在实现目标功能的基础上,又增加了额外功能.就像生活中的中介一样,他跟两边客户会有私下的交流. ②控制访问,代理不让用户直接和目标接触.就像中间商一样,他们不会让我们 ...

  4. Java动态代理的两种实现方法:JDK动态代理和CGLIB动态代理

    Java动态代理的两种实现方法:JDK动态代理和CGLIB动态代理 代理模式 JDK动态代理 CGLIB动态代理 代理模式 代理模式是23种设计模式的一种,指一个对象A通过持有另一个对象B,可以具有B ...

  5. 利用代码分别实现jdk动态代理和cglib动态代理_面试之动态代理

    大家好!我是CSRobot,从今天开始,我将会发布一些技术文章,内容就是结合春招以来的面试所遇到的问题进行分享,首先会对知识点进行一个探讨和整理,在最后会给出一些面试题并作出解答,希望可以帮助到大家! ...

  6. JDK动态代理和CGLib动态代理简单演示

    JDK1.3之后,Java提供了动态代理的技术,允许开发者在运行期间创建接口的代理实例. 一.首先我们进行JDK动态代理的演示. 现在我们有一个简单的业务接口Saying,如下: package te ...

  7. JAVA 进阶篇 动态代理 JDK动态代理和CGlib动态代理

    JDK动态代理和CGlib动态代理 JDK动态代理: 利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理. CGlib动态代理: 利用ASM(开源的Java ...

  8. jdk动态代理和cglib动态代理实现及区别

    代理模式是一种设计模式,提供了对目标对象额外的访问方式,即通过代理对象访问目标对象,这样可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标对象的功能. 代理模式又分为:静态代理.jdk动态代 ...

  9. Java两种动态代理JDK动态代理和CGLIB动态代理

    目录 代理模式 JDK动态代理 cglib动态代理 测试 代理模式 代理模式是23种设计模式的一种,他是指一个对象A通过持有另一个对象B,可以具有B同样的行为的模式.为了对外开放协议,B往往实现了一个 ...

  10. 【Spring6】| GoF之代理模式(JDK动态代理和CGLIB动态代理)

    目录 一:GoF之代理模式 1. 对代理模式的理解 2. 静态代理 3. 动态代理 3.1 JDK动态代理 3.2 CGLIB动态代理 一:GoF之代理模式 1. 对代理模式的理解 生活场景1:牛村的 ...

最新文章

  1. 【组队学习】【30期】时间序列分析
  2. Python模块学习——optparse
  3. python软件在哪里自学好_python自学教程【安装python及第一个程序】
  4. 最全三大框架整合(使用映射)——DeptDaoImpl.java
  5. JDK 12 Early Access Build 12中的原始字符串文字支持
  6. mysql 插入中文 ERROR 1366 (HY000): Incorrect string value: '\xE7\x8E\x9E\x97' for column
  7. Python基础学习笔记三
  8. 想学好编程,别背代码!
  9. 详解Java中的正则表达式
  10. windows2003 ftp 无法下载 解决
  11. python有比赛吗_python编程比赛到底应不应该让孩子参加?有好处
  12. 计算机应用的核心能力,应用能力为核心的高职计算机应用分析
  13. 近期关于感知器MLP的最新研究
  14. IC卡防复制 设备联网 动态密钥方案说明 一卡通 门禁卡防破解Mifare卡低成本动态加密实现思路
  15. 手机Linux安装rtl8187L,fedora 19编译安装rtl8187l驱动问题
  16. 计算机上的根号计算公式,根号计算公式
  17. 原来小米手机的电源键不止能用来关机,这么多实用功能,别浪费了
  18. 如何入门网络爬虫,摸索一年的心里路程
  19. Postman安装与基本操作
  20. 3D 渲染和游戏引擎技术信息来源

热门文章

  1. lomboz连接mysql数据库_『在线等』 lomboz-eclipse连接mysql,连接失败
  2. jquery进度条插件
  3. CRUISE软件测试工程师,CruiseControl.NET配置
  4. 死链检测工具Xenu的操作及使用方法
  5. 遗传算法matlab_通俗易懂地解释遗传算法
  6. 尔雅 科学通史(吴国盛) 个人笔记及课后习题 2018 第五章 欧洲科技文明的起源
  7. 免费收录网站搜索引擎登录口大全
  8. Python 数据可视化学习笔记 之高维数据可视化及其方法
  9. BAT智能硬件布局 争搭平台卡位各异
  10. VirtualBox安装Win10系统