JDK代理模式
代理模式
代理模式是一种通过代理对象来代替真实对象,而可以在不修改原有对象的前提下,提供额外的功能操作,扩展目标对象的功能
静态代理
静态代理中,对目标对象的每个方法的增强都是手动完成的,在接口新增一些方法,目标对象和代理对象都需要进行修改(使用场景非常少)
动态代理
相比较于静态代理来说,动态代理更加灵活。我们不需要针对每个目标类都单独创建一个代理类,我们可以直接使用代理对象实现类(CGLB动态动态代理机制)
动态代理实现
JDK动态代理
在 Java 动态代理机制中 InvocationHandler
接口和 Proxy
类是核心。
1 | /** |
1 | /** |
3.1.2. JDK 动态代理类使用步骤
- 定义一个接口及其实现类;
- 自定义
InvocationHandler
并重写invoke
方法,在invoke
方法中我们会调用原生方法(被代理类的方法)并自定义一些处理逻辑; - 通过
Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
方法创建代理对象;
java中InvocationHandler接口中第一个参数proxy详解
CGLB动态代理
JDK动态代理只能代理实现了接口的类
CGLIB(Code Generation Library)是一个基于ASM的字节码生成库,它允许我们在运行时对字节码进行修改和动态生成。CGLIB 通过继承方式实现代理。很多知名的开源框架都使用到了CGLIB, 例如 Spring 中的 AOP 模块中:如果目标对象实现了接口,则默认采用 JDK 动态代理,否则采用 CGLIB 动态代理。
在 CGLIB 动态代理机制中 MethodInterceptor
接口和 Enhancer
类是核心。
1 | /* |
CGLIB 动态代理类使用步骤
定义一个类;
自定义 MethodInterceptor
并重写 intercept
方法,intercept
用于拦截增强被代理类的方法,和 JDK 动态代理中的 invoke
方法类似;
通过 Enhancer
类的 create()
创建代理类;
代码示例
不同于 JDK 动态代理不需要额外的依赖
1 | <dependency> |
实现一个使用阿里云发送短信的类
1
2
3
4
5
6
7
8package github.javaguide.dynamicProxy.cglibDynamicProxy;
public class AliSmsService {
public String send(String message) {
System.out.println("send message:" + message);
return message;
}
}自定义
MethodInterceptor
(方法拦截器)
1 | import net.sf.cglib.proxy.MethodInterceptor; |
- 获取代理类
1 | import net.sf.cglib.proxy.Enhancer; |
- 实际使用
1 | AliSmsService aliSmsService = (AliSmsService) CglibProxyFactory.getProxy(AliSmsService.class); |
JDK 动态代理和 CGLIB 动态代理对比
- JDK 动态代理只能代理实现了接口的类或者直接代理接口,而 CGLIB 可以代理未实现任何接口的类。 另外, CGLIB 动态代理是通过生成一个被代理类的子类来拦截被代理类的方法调用,因此不能代理声明为 final 类型的类和方法。
- 就二者的效率来说,大部分情况都是 JDK 动态代理更优秀,随着 JDK 版本的升级,这个优势更加明显。