静态代理、JDK/CGLIB 动态代理
1、代理模式
简单来说就是我们使用代理对象代替对真实对象的访问,在不改变真实对象的前提下,提供额外的功能操作,增强目标对象的功能。
代理模式可分为静态代理和动态代理两种方式
2、静态代理
2.1 描述
静态代理需要手写代理实现类去实现接口,并去重写接口中的每个方法。
非常不灵活且麻烦,因为需要对每一个目标对象创建一个实现类;而且一旦接口中新增一个方法,目标对象和实现类都需要进行相应的调整。
从 JVM 层面来说,静态代理在编译期就已经将接口、实现类、代理类编译成 .class
文件了。
2.2 实现步骤
- 定义一个接口和实现类;
- 创建一个代理实现类同样实现这个接口;
- 将目标对象注入到代理类,然后在代理类的对应方法调用目标对象的相应方法
2.3 场景实践
现在设计一个发送短信的场景,对发送短信接口作增强,手写一个发短信增强的静态代理类
2.3.1 定义发送短信接口
public interface SmsService {
String send(String message);
}
2.3.2 定义发送短信接口实现类
public class SmsServiceImpl implements SmsService {
@Override
public String send(String message) {
System.out.println("发送短信内容:" + message);
return message;
}
}
2.3.3 创建代理类并实现同样的接口
public class SmsProxy implements SmsService {
private final SmsService smsService;
public SmsProxy(SmsService smsService) {
this.smsService = smsService;
}
@Override
public String send(String message) {
System.out.println("发送短信之前,可添加操作");
smsService.send(message);
System.out.println("发送短信之后,可添加操作");
return message;
}
}
2.3.4 代码测试
public class ProxyTest {
public static void main(String[] args) {
// 1、静态代理
staticProxy();
}
/**
* 静态代理测试
*/
public static void staticProxy() {
// 真实对象
SmsService smsService = new SmsServiceImpl();
// 代理对象
SmsProxy smsProxy = new SmsProxy(smsService);
// 使用代理对象代替对真实对象的访问,
// 在不改变原目标对象的情况下,提供额外的功能操作,扩展目标对象的功能;
smsProxy.send("静态代理--发短信给小马");
}
}
方法运行后输出内容:
发送短信之前,可添加操作
发送短信内容:静态代理--发短信给小马
发送短信之后,可添加操作
从输出结果可以清晰的看到,在执行发送短信业务前后分别执行了我们设计的增强功能。
3、动态代理
与静态代理相比,动态代理更加灵活。我们不需要针对每一个目标对象都单独创建一个代理类,并且也不必须要实现接口,可以直接代理类。
从 JVM
层面来说,动态代理是在运行时期动态生成类字节码并加载到 JVM
中去。
动态代理的实现方式有很多种,最主要的还是 JDK 动态代理 和 CGLIB 动态代理。