前言
代理模式是 Java 中常见的设计模式之一,它的核心思想是通过一个代理对象来控制对真实对象的访问。代理模式不仅可以扩展目标对象的功能,而且在不修改原目标对象的情况下,可以增加一些我们自定义的操作。

1. 代理模式简介
代理模式的核心思想是:通过代理对象来代替对真实对象的访问。这样做的好处是,我们可以在不修改原目标对象的前提下,扩展目标对象的功能。比如,在目标对象的某个方法执行前后,你可以增加一些自定义的操作。
举个例子:
新娘找来了自己的闺蜜来代替自己处理新郎的提问。新娘收到的提问都是经过闺蜜处理过滤之后的。闺蜜在这里就可以看作是新娘的代理对象,代理的行为(方法)是接收和回复新郎的提问。
再举个例子:
你是一个明星,每天有很多粉丝找你签名。但你是大忙人,没时间亲自处理这些请求,所以你找了一个经纪人(代理对象)来帮你处理。粉丝的请求先交给经纪人,经纪人再决定是否转交给你,或者帮你做一些额外的处理(比如记录谁来找你签名)。这样,你既不用亲自处理所有请求,又能保证签名工作顺利进行。
2. 静态代理
2.1 什么是静态代理?
静态代理是指,在编译时就已经确定了代理类和目标类的关系。我们需要手动为每个目标类创建一个代理类,并在代理类中调用目标类的方法。
静态代理的缺点:灵活性较差,一旦接口新增方法,目标类和代理类都需要进行修改。
2.2 静态代理的实现步骤
- 定义一个接口及其实现类;
- 创建一个代理类并实现该接口;
- 将目标对象注入代理类,并在代理类的方法中调用目标类的方法。
2.3 代码示例
1. 定义发送短信的接口
java
public interface SmsService {
String send(String message);
}
2. 实现发送短信的接口
java
public class SmsServiceImpl implements SmsService {
public String send(String message) {
System.out.println("send message:" + message);
return message;
}
}
3. 创建代理类并实现发送短信的接口
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.send(message);
// 调用方法之后,我们同样可以添加自己的操作
System.out.println("after method send()");
return null;
}
}
4. 实际使用
java
public class Main {
public static void main(String[] args) {
SmsService smsService = new SmsServiceImpl();
SmsProxy smsProxy = new SmsProxy(smsService);
smsProxy.send("java");
}
}
运行上述代码之后,控制台打印出:
java
before method send()
send message:java
after method send()
可以看到,我们成功地在 SmsServiceImpl
的 send()
方法前后增加了自定义操作。
3. 动态代理
3.1 什么是动态代理?
相比于静态代理,动态代理更加灵活。我们不需要针对每个目标类都单独创建一个代理类,而是可以在运行时动态生成代理类。动态代理的实现方式有很多种,比如 JDK 动态代理和 CGLIB 动态代理。
3.2 JDK 动态代理
3.2.1 JDK 动态代理的核心
在 JDK 动态代理中,InvocationHandler
接口和 Proxy
类是核心。Proxy
类的 newProxyInstance()
方法用于生成代理对象,而 InvocationHandler
接口的 invoke()
方法则用于处理代理对象的方法调用。
3.2.2 JDK 动态代理的实现步骤
- 定义一个接口及其实现类;
- 自定义
InvocationHandler
并重写invoke
方法;- 通过
Proxy.newProxyInstance()
方法创建代理对象。
3.2.3 代码示例
1. 定义发送短信的接口
java
public interface SmsService {
String send(String message);
}
2. 实现发送短信的接口
java
public class SmsServiceImpl implements SmsService {
public String send(String message) {
System.out.println("send message:" + message);
return message;
}
}
3. 定义一个 JDK 动态代理类
java
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class DebugInvocationHandler implements InvocationHandler {
private final Object target;
public DebugInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before method " + method.getName());
Object result = method.invoke(target, args);
System.out.println("after method " + method.getName());
return result;
}
}
4. 获取代理对象的工厂类
java
import java.lang.reflect.Proxy;
public class JdkProxyFactory {
public static Object getProxy(Object target) {
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new DebugInvocationHandler(target)
);
}
}
5. 实际使用
java
public class Main {
public static void main(String[] args) {
SmsService smsService = (SmsService) JdkProxyFactory.getProxy(new SmsServiceImpl());
smsService.send("java");
}
}
运行上述代码之后,控制台打印出:
java
before method send
send message:java
after method send
3.3 CGLIB 动态代理
3.3.1 CGLIB 动态代理的核心
CGLIB 动态代理通过继承目标类来生成代理类,因此它可以代理未实现任何接口的类。CGLIB 的核心是 MethodInterceptor
接口和 Enhancer
类。
3.3.2 CGLIB 动态代理的实现步骤
- 定义一个类;
- 自定义
MethodInterceptor
并重写intercept
方法;- 通过
Enhancer
类的create()
方法创建代理类。
3.3.3 代码示例
1. 实现一个使用阿里云发送短信的类
java
public class AliSmsService {
public String send(String message) {
System.out.println("send message:" + message);
return message;
}
}
2. 自定义 MethodInterceptor
java
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class DebugMethodInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("before method " + method.getName());
Object object = methodProxy.invokeSuper(o, args);
System.out.println("after method " + method.getName());
return object;
}
}
3. 获取代理类
java
import net.sf.cglib.proxy.Enhancer;
public class CglibProxyFactory {
public static Object getProxy(Class<?> clazz) {
Enhancer enhancer = new Enhancer();
enhancer.setClassLoader(clazz.getClassLoader());
enhancer.setSuperclass(clazz);
enhancer.setCallback(new DebugMethodInterceptor());
return enhancer.create();
}
}
4. 实际使用
java
public class Main {
public static void main(String[] args) {
AliSmsService aliSmsService = (AliSmsService) CglibProxyFactory.getProxy(AliSmsService.class);
aliSmsService.send("java");
}
}
运行上述代码之后,控制台打印出:
java
before method send
send message:java
after method send
4. 静态代理和动态代理的对比
- 灵活性:动态代理更加灵活,不需要针对每个目标类都创建一个代理类,且可以直接代理实现类。
- JVM 层面:静态代理在编译时生成 class 文件,而动态代理在运行时动态生成类字节码。