提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
- 前言
- 1、定义
- 2、结构
- 3、实现方式
-
- [3.1 静态代理](#3.1 静态代理)
- [3.2 动态代理](#3.2 动态代理)
-
- [3.2.1 JDK动态代理](#3.2.1 JDK动态代理)
- [3.2.2 CGLIB动态代理](#3.2.2 CGLIB动态代理)
- 总结
前言
- 某个客户端不能直接操作到某个对象,但又必须和那个对象有所互动
- 如果对象是一个大图片,需要花费很长时间才能显示出来,此时需要做个图片Proxy来代替真正的图片。
- 如果对象在某远端服务器上,直接操作这个对象因为网络速度原因可能比较慢,那么可以先用Proxy来代替那个对象。
1、定义
代理模式是为其他对象提供一种代理以控制对这个对象的访问。
代理模式的主要作用是扩展目标对象的功能,比如说在目标对象的某个方法执行前后可以增加一些自定义的操作。
2、结构

代理模式的参与者:
- Proxy:代理主题角色
- 保存一个引用使得代理可以访问实体
- 提供一个与Subject的相同的接口,这样代理就可以用来替代实体。
- 控制对实体的存取,并可能负责创建和删除它。
- 其他功能依赖于代理的类型。
- Subject:抽象主题角色
- 定义ConcreteSubject和Proxy的共用接口,在任何使用ConcreteSubject的敌方都可以使用Proxy。
- RealSubject:真实主题角色
- 定义Proxy所代表的实体
3、实现方式
3.1 静态代理
实现流程:
1、定义一个接口及实现类
2、创建一个代理类同样实现这个接口
3、将目标对象注入进代理类,然后在代理类的对应方法调用目标类中的对应方法
以短信发送为例:
步骤1如下:
java
public interface SmsService {
/**
* 发送短信
* @param phone 手机号(如+8613812345678)
* @param params 模板参数
* @return 是否发送成功
*/
boolean sendSms(String phone, String[] params);
}
java
@Service
public class SmsServiceImpl implements SmsService {
@Override
public boolean sendSms(String phone, String[] params) {
// 实现发送短信的方法
}
}
步骤2如下:
java
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("before method send()");
smsService.sendSms(message);
System.out.println("after method send()");
return null;
}
}
3.2 动态代理
动态代理不需要针对每个目标类都单独创建一个代理类,并且也不需要必须实现接口,可以直接代理实现类。
从JVM角度来说,动态代理是在运行时动态生成类字节码,并加载到JVM中的。
Spring AOP、RPC框架实现都依赖了动态代理
3.2.1 JDK动态代理
Java动态代理机制中,InvocationHander接口和proxy类是核心
Proxy类中使用频率最高的方法是newProxyInstance(),这个方法主要用来生成一个代理对象。
java
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
......
}
- loader:类加载器,用于加载代理对象
- interfaces:被代理类实现的一些接口
- h:实现了
InvocationHandler接口的对象
要实现动态代理,必须要实现InvocationHandler来自定义处理逻辑。当动态代理调用一个方法时,这个方法的调用就会被转发到实现InvocationHandler接口类的invoke方法来调用。
java
public interface InvocationHandler {
/**
* 当你使用代理对象调用方法的时候实际会调用到这个方法
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
invoke()方法有3个参数:
- proxy:动态生成的代理类
- method:与代理类对象调用的方法相对应
- args:当前method方法的参数
3.2.2 CGLIB动态代理
CGLIB是一个基于ASM的字节码生成库,它允许在运行时对字节码进行修改和动态生成。CGLIB通过继承方式实现代理。