动态代理是为了实现Aop编程(不修改类源码,类方法执行前后,自定义增强处理, 日志 拦截等等),代理的是类对象

一、jdk动态代理

被代理的类需要实现接口,针对接口的代理,通过生成一个实现了接口的动态类实现代理

  • ServiceImpl是被代理类,实现接口ServiceInterface
  • JDKProxy是代理处理方法类,实现接口InvocationHandler
  • 通过JDKProxy.bind()得到jdk【动态生成】代理类ServiceProxy (ServiceInterface),当你调用ServiceProxy.doService()会执行JDKProxy的invoke()方法,实现代理
//ServiceInterface.java
public interface ServiceInterface {public void doService();
}//ServiceImpl.java
public class ServiceImpl implements ServiceInterface {public void doService() {System.out.println("ServiceImpl");}
}//JDKProxy.java
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;public class JDKProxy implements InvocationHandler {private Object target = null;public Object bind(Object target) {this.target = target;return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);}public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("before method:"+method.getName());Object res = method.invoke(target,args);System.out.println("after method");return res;}public static void main(String[] args) {ServiceInterface service = (ServiceInterface) new JDKProxy().bind(new ServiceImpl());service.doService();}}

二、cglib动态代理

通过生成被代理类的【子类】实现代理,所以 Cglib是无法代理final修饰的方法或类

  • ServiceImpl是被代理类
  • ServiceProxy是代理处理类,实现接口MethodInterceptor
  • 通过ServiceProxy.getProxy()动态生成被代理类子类ServiceImpl_SubClass (ServiceImpl)当你调ServiceImpl_SubClass.doService()会执行ServiceProxy.Intercept()方法,实现代理
//ServiceInterface.java
public interface ServiceInterface {public void doService();
}//ServiceImpl.java
public class ServiceImpl implements ServiceInterface{public void doService() {System.out.println("ServiceImpl");}
}//ServiceProxy.java
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;import java.lang.reflect.Method;public class ServiceProxy implements MethodInterceptor {private Enhancer enhancer = new Enhancer();/**通过cglib方式创建动态代理对象Enhancer.setClassLoader()Enhancer.setSuperClass()Enhancer.setCallback();  ---> MethodInterceptor(cglib)Enhancer.create() ---> 代理*/public Object getProxy(Class clazz) {enhancer.setSuperclass(clazz);enhancer.setCallback(this);return enhancer.create();}public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {System.out.println("before method:" + method.getName());Object res = methodProxy.invokeSuper(o, objects);System.out.println("after method");return res;}public static void main(String[] args) {ServiceInterface service = (ServiceImpl) new ServiceProxy().getProxy(ServiceImpl.class);service.doService();}
}
        //pom.xml<dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>2.2.2</version></dependency>

上面的jdk与cglib动态代理例子,没有改变ServiceInterface接口与ServiceImpl实现类代码,通过一个代理处理类实现动态对ServiceImpl的代理,方法执行前后增强处理,打印日志,也可以通过try catch捕获方法中的异常实现事务控制等等

三、两者的切换

  1. JDK动态代理 Proxy.newProxyInstance() 通过接口创建代理的实现类
  2. Cglib动态代理 Enhancer 通过继承父类创建的代理类 (没有实现接口的话spring底层就切换成CGLib的方式)

四、Spring动态代理用JDK还是用CGLIB

动态代理又有两种实现方式:

  • 一种方法是直接实现JDK中的InvocationHandler接口
  • 另一种方法是继承CGLIB。

那么问题来了,这两种方法有啥区别呢,分别适用于什么情况呢?

首先如果不是很清楚两者的区别的话,记住一般情况下InvocationHandler要比CGLIB要好就行了。

如果目标对象的代理至少实现了一个接口,那么就用JDK动态代理,所有由目标对象实现的接口将全部都被代理。如果目标对象没有实现任何接口,那么就用CGLIB代理。

但是如果非要使用CGLIB的话,那么CGLIB可能有下面的问题:

刚才提到了,InvocationHandler是实现的接口,而CGLIB则是继承的父类,那么由于继承的限制,如果父类中有final的成员,那么是继承不到的。

还有从Spring 3.2以后不再将CGLIB放在项目的classpath下,而是将CGLIB类打包放在spring-core下面的org.springframework中。这个就意味着基于CGLIB的动态代理与JDK的动态代理在支持“just works”就一样了。

在Spring 4.0中,因为CGLIB代理实例是通过Objenesis创建的,所以代理对象的构造器不再有两次调用。

想要强制使用CGLIB,那么就设置aop:config下面的proxy-target-class属性为true:

<aop:config proxy-target-class="true"><!-- other beans defined here... -->
</aop:config>

要是使用@AspectJ强制使用CGLIB的话,可以配置aop:aspectj-autoproxy下的proxy-target-class属性为true:

<aop:aspectj-autoproxy proxy-target-class="true"/>

注意: Spring AOP 代理默认实现 JDK SpringBOOT AOP 代理默认实现 Cglib
参考文章1
参考文章2

jdk动态代理与cglib动态代理--InvocationHandler--MethodInterceptor相关推荐

  1. 你必须会的 JDK 动态代理和 CGLIB 动态代理

    来自:ytao 我们在阅读一些 Java 框架的源码时,基本上常会看到使用动态代理机制,它可以无感的对既有代码进行方法的增强,使得代码拥有更好的拓展性.通过从静态代理.JDK 动态代理.CGLIB 动 ...

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

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

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

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

  4. jdk动态代理与cglib动态代理例子

    1.JAVA的动态代理特征:特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等.代理类与委托类之间通常会存在关联关系,一个代理类的对象 ...

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

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

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

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

  7. 一文理解JDK静态代理、JDK动态代理、Cglib动态代理

    代理模式 通过代理来访问真实的对象,而不是直接去访问真正干活的对象,比如二房东租房,二房是代理者,而一房东才是真正的房东:或者说生活中的中介.Spring中的AOP就是动态代理 适用场景 需要动态修改 ...

  8. JDK 动态代理与 CGLIB 动态代理,它俩真的不一样

    摘要:一文带你搞懂JDK 动态代理与 CGLIB 动态代理 本文分享自华为云社区<一文带你搞懂JDK 动态代理与 CGLIB 动态代理>,作者: Code皮皮虾 . 两者有何区别 1.Jd ...

  9. 浅谈Spring中JDK动态代理与CGLIB动态代理

    前言 Spring是Java程序员基本不可能绕开的一个框架,它的核心思想是IOC(控制反转)和AOP(面向切面编程).在Spring中这两个核心思想都是基于设计模式实现的,IOC思想的实现基于工厂模式 ...

  10. Spring 静态代理+JDK动态代理和CGLIB动态代理

    代理分为两种:静态代理 动态代理 静态代理:本质上会在硬盘上创建一个真正的物理类 动态代理:本质上是在内存中构建出一个类. 如果多个类需要进行方法增强,静态代理则需要创建多个物理类,占用磁盘空间.而动 ...

最新文章

  1. 《Unity 3.x游戏开发实例》一1.5 欢迎来到Unity 3D
  2. Xilinx SDK使用教程
  3. 如何对用户进行细分-邮件营销中用户细分的方法
  4. 【毕业答辩】毕业设计答辩前期准备
  5. String类的实现
  6. excel文件损坏修复绝招_电脑常识:电脑提示dll文件丢失/损坏,该怎么修复?...
  7. 离散数学之数理逻辑01
  8. 分享110个采集小偷PHP源码,总有一款适合你
  9. Python分析00-90后的微信昵称,发现如下规律!
  10. GTD时间管理工具Omnifocus 3 Mac中文版
  11. KingabseES 锁机制
  12. UEFI+GPT引导实践篇 (UEFI引导安装64位Win7/Win8)
  13. moto XT316 刷机+ROOT权限获取
  14. MySQL连接查询,子查询,union(合并),分页
  15. ***虚拟专用网技术
  16. 《阿凡达2》上映在即,3D渲染如何突破想象?
  17. python cmd以管理员执行指令(网卡切断与打开)
  18. [Elasticsearch](五)Docker环境下搭建Elasticsearch,Elasticsearch集群,Elasticsearch-Head以及IK分词插件和拼音分词插件
  19. 小学计算机基础知识汇总,电脑基础知识:内存条知识大全,看完小学生都了解...
  20. 网络安全相关基础知识

热门文章

  1. csharp: DataTable export to excel,word,csv etc
  2. 锁定文件失败 打不开磁盘“D:\vms\S1\CentOS 64 位.vmdk”或它所依赖的某个快照磁盘(强制关机后引起的问题)...
  3. cron和crontab
  4. redis入门(02)redis的常见问题
  5. [Effective JavaScript 笔记]第29条:避免使用非标准的栈检查属性
  6. PHP的isset()和empty()比较
  7. Python列表排序 reverse、sort、sorted 操作方法详解
  8. Go 语言框架 Gin 练习1
  9. android 常见分辨率(mdpi、hdpi 、xhdpi、xxhdpi )及屏幕适配注意事
  10. 使用libsvm实现归一化