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