动态代理在Java中有着广泛的应用,比如Spring AOP,Hibernate数据查询、RPC等,Java中两种常见的动态代理方式有:JDK原生动态代理和CGLIB动态代理。
下面我们就来谈谈两者的区别。
JDK动态代理
Java 提供了动态代理技术,允许开发者在运行期创建接口的代理实例,后来这项技术被用到了 Spring 的很多地方。
JDK 动态代理主要涉及 java.lang.reflect 包下边的两个类:Proxy 和 InvocationHandler。其中,InvocationHandler 是一个接口,可以通过实现该接口定义横切逻辑(如:我们在方法执行前后打印的日志,本文只是为了演示,实际的应用一般不会只是简单的打印日志的),并通过反射机制调用目标类的代码,动态地将横切逻辑和业务逻辑编织在一起。
JDK 动态代理是不需要第三方库支持,只需要 JDK 环境就可以进行代理,使用条件
- 业务目标对象实现接口
- 实现 InvocationHandler 接口
- 使用 Proxy.newProxyInstance() 方法生成代理对象
JDK 动态代理的话,它有一个限制,就是它只能为接口创建代理实例,而对于没有通过接口定义业务方法的类,如何创建动态代理实例哪?答案就是 CGLib。
CGLib动态代理
CGLIB是一个功能强大,高性能的代码生成包,它为没有实现接口的类提供代理,为JDK的动态代理提供了很好的补充。
静态代理和 JDK 动态代理模式都要求目标对象是实现一个接口,但是有时候目标对象只是一个单独的对象,并没有实现任何的接口,这个时候可使用目标对象子类来实现代理-这就是 Cglib 代理。
Cglib 是一个强大的高性能的代码生成包,它可以在运行期扩展 java 类与实现 java 接口,它广泛的被许多 AOP 的框架使用,例如 Spring AOP,实现方法拦截
在 AOP 编程中如何选择代理模式:
- 目标对象需要实现接口,用 JDK 代理
- 目标对象不需要实现接口,用 Cglib 代理
通常可以使用Java的动态代理创建代理,但当要代理的类没有实现接口或者为了更好的性能,CGLIB是一个好的选择。
CGLib与JDK动态代理的区别
1.实现的区别
JDK动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。
CGLib动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。
2.使用的区别
JDK 动态代理只能针对接口实现类生成代理实例,而不能针对类,也就是说它是面向接口的;
CGLIB 是针对类实现代理,主要是对指定的类生成一个子类,并覆盖其中方法实现增强,CGLIB 因为采用的是继承,所以该类或方法最好不要声明成 final,对于 final 类或方法,是无法继承的;
3.性能的区别
CGLib所创建的动态代理对象在实际运行时候的性能要比JDK动态代理高不少;
但是CGLib在创建对象的时候所花费的时间却比JDK动态代理要多很多;
4.创建的区别
对于singleton的代理对象或者具有实例池的代理,因为无需频繁的创建代理对象,所以比较适合采用CGLib动态代理,反正,则比较适用JDK动态代理。
3.Spring选择区别
Bean实现接口,选用JDK
Bean没有实现接口,选用CGLIB
陈睿mikechen
10年+大厂架构经验,资深技术专家,就职于阿里巴巴、淘宝、百度等一线互联网大厂。
关注「mikechen」公众号,获取更多技术干货!
后台回复【面试】即可获取《史上最全阿里Java面试题总结》,后台回复【架构】,即可获取《阿里架构师进阶专题全部合集》