代理模式UML类图
0x01 静态代理
这种代理方式需要代理对象和目标对象实现一样的接口。
优点:可以在不修改目标对象的前提下扩展目标对象的功能。
缺点:
- 冗余。由于代理对象要实现与目标对象一致的接口,会产生过多的代理类。
- 不易维护。一旦接口增加方法,目标对象与代理对象都要进行修改。
demo
1 | /** |
1 | /** |
1 | /** |
1 | /** |
0x02 动态代理
动态代理利用了JDK API,动态地在内存中构建代理对象,从而实现对目标对象的代理功能。动态代理又被称为JDK代理或接口代理。
静态代理与动态代理的区别主要在:
- 静态代理在编译时就已经实现,编译完成后代理类是一个实际的class文件
- 动态代理是在运行时动态生成的,即编译完成后没有实际的class文件,而是在运行时动态生成类字节码,并加载到JVM中
特点:
动态代理对象不需要实现接口,但是要求目标对象必须实现接口,否则不能使用动态代理。
- JDK动态代理主要涉及的类
1 | static Object newProxyInstance(ClassLoader loader, //指定当前目标对象使用类加载器 |
dynamic proxy demo
1 | /** |
1 | /** |
1 | /** |
0x03 Cglib代理
cglib特点
- JDK的动态代理有一个限制,就是使用动态代理的对象必须实现一个或多个接口。
如果想代理没有实现接口的类,就可以使用CGLIB实现。 - CGLIB是一个强大的高性能的代码生成包,它可以在运行期扩展Java类与实现Java接口。
它广泛的被许多AOP的框架使用,例如Spring AOP和dynaop,为他们提供方法的interception(拦截)。 - CGLIB包的底层是通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类。
不鼓励直接使用ASM,因为它需要你对JVM内部结构包括class文件的格式和指令集都很熟悉。
cglib与动态代理最大的区别就是
- 使用动态代理的对象必须实现一个或多个接口
- 使用cglib代理的对象则无需实现接口,达到代理类无侵入。
- cglib通过继承实现代理,所以它无法代理final类型
cglib demo
1 | package com.cglib; |
1 | package com.cglib; |
1 | package com.cglib; |
0x04 面试题
来源于网上,用于帮助理解和掌握,欢迎补充
1. 描述动态代理的几种实现方式?分别说出相应的优缺点
代理可以分为 “静态代理” 和 “动态代理”,动态代理又分为 “JDK动态代理” 和 “CGLIB动态代理” 实现。
静态代理:代理对象和实际对象都继承了同一个接口,在代理对象中指向的是实际对象的实例,这样对外暴露的是代理对象而真正调用的是 Real Object
- 优点:可以很好的保护实际对象的业务逻辑对外暴露,从而提高安全性。
- 缺点:不同的接口要有不同的代理类实现,会很冗余
JDK 动态代理:
- 为了解决静态代理中,生成大量的代理类造成的冗余;
- JDK 动态代理只需要实现 InvocationHandler 接口,重写 invoke 方法便可以完成代理的实现,
- jdk的代理是利用反射生成代理类 Proxyxx.class 代理类字节码,并生成对象
- jdk动态代理之所以只能代理接口是因为代理类本身已经extends了Proxy,而java是不允许多重继承的,但是允许实现多个接口
- 优点:解决了静态代理中冗余的代理实现类问题。
- 缺点:JDK 动态代理是基于接口设计实现的,如果没有接口,会抛异常。
CGLIB 代理:
- 由于 JDK 动态代理限制了只能基于接口设计,而对于没有接口的情况,JDK方式解决不了;
- CGLib 采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑,来完成动态代理的实现。
- 实现方式实现 MethodInterceptor 接口,重写 intercept 方法,通过 Enhancer 类的回调方法来实现。
- 但是CGLib在创建代理对象时所花费的时间却比JDK多得多,所以对于单例的对象,因为无需频繁创建对象,用CGLib合适,反之,使用JDK方式要更为合适一些。
- 同时,由于CGLib由于是采用动态创建子类的方法,对于final方法,无法进行代理。
- 优点:没有接口也能实现动态代理,而且采用字节码增强技术,性能也不错。
- 缺点:技术实现相对难理解些。
2. CGlib 对接口实现代理?
1 | import net.sf.cglib.proxy.Enhancer; |
参考
[CGlib动态代理原理](
- 本文作者: Noisy
- 本文链接: http://Metatronxl.github.io/2019/11/12/Java-静态代理、动态代理、cglib代理/
- 版权声明: 本博客所有文章除特别声明外,均采用 Apache License 2.0 许可协议。转载请注明出处!