jdk动态代理与cglib动态代理--InvocationHandler--MethodInterceptor
动态代理是为了实现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捕获方法中的异常实现事务控制等等
三、两者的切换
- JDK动态代理 Proxy.newProxyInstance() 通过接口创建代理的实现类
- 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相关推荐
- 你必须会的 JDK 动态代理和 CGLIB 动态代理
来自:ytao 我们在阅读一些 Java 框架的源码时,基本上常会看到使用动态代理机制,它可以无感的对既有代码进行方法的增强,使得代码拥有更好的拓展性.通过从静态代理.JDK 动态代理.CGLIB 动 ...
- 什么是代理模式?代理模式有什么用?通过一个小程序分析静态代理和动态代理。自己简单实现动态代理。JDK动态代理和CGLIB动态代理的区别。
1. 代理模式有什么用 ①功能增强,在实现目标功能的基础上,又增加了额外功能.就像生活中的中介一样,他跟两边客户会有私下的交流. ②控制访问,代理不让用户直接和目标接触.就像中间商一样,他们不会让我们 ...
- Java动态代理的两种实现方法:JDK动态代理和CGLIB动态代理
Java动态代理的两种实现方法:JDK动态代理和CGLIB动态代理 代理模式 JDK动态代理 CGLIB动态代理 代理模式 代理模式是23种设计模式的一种,指一个对象A通过持有另一个对象B,可以具有B ...
- jdk动态代理与cglib动态代理例子
1.JAVA的动态代理特征:特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等.代理类与委托类之间通常会存在关联关系,一个代理类的对象 ...
- 利用代码分别实现jdk动态代理和cglib动态代理_面试之动态代理
大家好!我是CSRobot,从今天开始,我将会发布一些技术文章,内容就是结合春招以来的面试所遇到的问题进行分享,首先会对知识点进行一个探讨和整理,在最后会给出一些面试题并作出解答,希望可以帮助到大家! ...
- JDK动态代理和CGLib动态代理简单演示
JDK1.3之后,Java提供了动态代理的技术,允许开发者在运行期间创建接口的代理实例. 一.首先我们进行JDK动态代理的演示. 现在我们有一个简单的业务接口Saying,如下: package te ...
- 一文理解JDK静态代理、JDK动态代理、Cglib动态代理
代理模式 通过代理来访问真实的对象,而不是直接去访问真正干活的对象,比如二房东租房,二房是代理者,而一房东才是真正的房东:或者说生活中的中介.Spring中的AOP就是动态代理 适用场景 需要动态修改 ...
- JDK 动态代理与 CGLIB 动态代理,它俩真的不一样
摘要:一文带你搞懂JDK 动态代理与 CGLIB 动态代理 本文分享自华为云社区<一文带你搞懂JDK 动态代理与 CGLIB 动态代理>,作者: Code皮皮虾 . 两者有何区别 1.Jd ...
- 浅谈Spring中JDK动态代理与CGLIB动态代理
前言 Spring是Java程序员基本不可能绕开的一个框架,它的核心思想是IOC(控制反转)和AOP(面向切面编程).在Spring中这两个核心思想都是基于设计模式实现的,IOC思想的实现基于工厂模式 ...
- Spring 静态代理+JDK动态代理和CGLIB动态代理
代理分为两种:静态代理 动态代理 静态代理:本质上会在硬盘上创建一个真正的物理类 动态代理:本质上是在内存中构建出一个类. 如果多个类需要进行方法增强,静态代理则需要创建多个物理类,占用磁盘空间.而动 ...
最新文章
- 《Unity 3.x游戏开发实例》一1.5 欢迎来到Unity 3D
- Xilinx SDK使用教程
- 如何对用户进行细分-邮件营销中用户细分的方法
- 【毕业答辩】毕业设计答辩前期准备
- String类的实现
- excel文件损坏修复绝招_电脑常识:电脑提示dll文件丢失/损坏,该怎么修复?...
- 离散数学之数理逻辑01
- 分享110个采集小偷PHP源码,总有一款适合你
- Python分析00-90后的微信昵称,发现如下规律!
- GTD时间管理工具Omnifocus 3 Mac中文版
- KingabseES 锁机制
- UEFI+GPT引导实践篇 (UEFI引导安装64位Win7/Win8)
- moto XT316 刷机+ROOT权限获取
- MySQL连接查询,子查询,union(合并),分页
- ***虚拟专用网技术
- 《阿凡达2》上映在即,3D渲染如何突破想象?
- python cmd以管理员执行指令(网卡切断与打开)
- [Elasticsearch](五)Docker环境下搭建Elasticsearch,Elasticsearch集群,Elasticsearch-Head以及IK分词插件和拼音分词插件
- 小学计算机基础知识汇总,电脑基础知识:内存条知识大全,看完小学生都了解...
- 网络安全相关基础知识
热门文章
- csharp: DataTable export to excel,word,csv etc
- 锁定文件失败 打不开磁盘“D:\vms\S1\CentOS 64 位.vmdk”或它所依赖的某个快照磁盘(强制关机后引起的问题)...
- cron和crontab
- redis入门(02)redis的常见问题
- [Effective JavaScript 笔记]第29条:避免使用非标准的栈检查属性
- PHP的isset()和empty()比较
- Python列表排序 reverse、sort、sorted 操作方法详解
- Go 语言框架 Gin 练习1
- android 常见分辨率(mdpi、hdpi 、xhdpi、xxhdpi )及屏幕适配注意事
- 使用libsvm实现归一化