代理模式可以创造代理对象,替代对真实对象的访问。目的是在不修改原对象的前提下,扩展目标对象并提供额外的功能操作。
代理模式主要分为动态代理和静态代理两种实现方式。
动态代理
动态代理是在 JVM 运行时动态生成字节码,并加载到 JVM 中的。
JDK 动态代理
在 Java 动态代理机制中,InvocationHandler 和 Proxy 类是核心。
1 | /** |
过程
- 定义接口和接口实现类;
- 通过 Proxy.newProxyInstance() 方法创建代理对象;
- 重写 InvocationHandler 中的 invoke() 方法,自定义一些处理逻辑;
实例
以发送短信为例:
定义发送短信的接口
1
2
3
4
5
6
7/**
* 发送短信的接口
*/
public interface SmsService {
String send(String message);
}实现发送短信的接口
1
2
3
4
5
6
7
8
9
10
11/**
* 实现接口
*/
public class SmsServiceImpl implements SmsService {
public String send(String message) {
System.out.println("send " + message);
return message;
}
}定义生成代理对象的工厂类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39import java.lang.reflect.*;
/**
* 生成代理对象的工厂类
*/
public static class ProxyFactory {
// 代理接口的实现类
public static Object getProxy(Object target) {
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("proxy send " + args[0]);
return method.invoke(target, args);
}
}
);
}
// 代理接口
public static Object getInterfaceProxy(Class<?> inter) {
ClassLoader classLoader = inter.getClassLoader();
Class<?>[] interfaces = new Class[]{inter};
return Proxy.newProxyInstance(
classLoader,
interfaces,
new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(method.getName());
return "None";
}
}
);
}
}我们使用动态代理对象调用原对象的原生方法时,实际上是通过 invoke() 方法去调用被代理对象的原生方法。
使用动态代理类
1
2
3
4
5
6
7
8
9SmsService smsServiceimpl = (SmsService) ProxyFactory.getProxy(new SmsServiceImpl());
smsServiceimpl.send("new value");
// out:
// proxy send new value
// send new value
SmsService smsServiceimpl = (SmsService) ProxyFactory.getInterfaceProxy(SmsService.class);
// out:
// send
CGLIB 动态代理
CGLIB 通过生成一个被代理类的子类来拦截被代理类的方法调用。核心是 MethodInterceptor 接口和Enhancer 类。使用前需要添加依赖:
1 | <dependency> |
过程
- 定义一个类;
- 定义 MethodInterceptor 方法并重写 intercept(),该方法可以拦截增强被代理类的方法,和 JDK 动态代理中的 invoke() 类似;
- 通过 Enhancer 类的 create() 创建代理类;
实例
同样的发短信为例:
实现类
1
2
3
4
5
6public class AliSmsService {
public String send(String message) {
System.out.println("send message:" + message);
return message;
}
}自定义 MethodInterceptor
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* 自定义MethodInterceptor
*/
public class DebugMethodInterceptor implements MethodInterceptor {
/**
* @param o 代理对象(增强的对象)
* @param method 被拦截的方法(需要增强的方法)
* @param args 方法入参
* @param methodProxy 用于调用原始方法
*/
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;
}
}获取代理类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17import 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();
}
}使用
1
2
3
4
5
6
7AliSmsService aliSmsService = (AliSmsService) CglibProxyFactory.getProxy(AliSmsService.class);
aliSmsService.send("java");
// out
// before method send
// send message:java
// after method send
JDK 动态代理和 CGLIB 动态代理比较
- JDK 动态代理只能代理接口实现类或者接口。
- CGLIB 可以代理未实现任何接口的类,但是该类不能声明为 final。
- JDK 的动态代理效率更高,优势明显。
静态代理
静态代理实际应用的场景很少,日常几乎不使用静态代理。
过程
- 定义一个接口及其实现类;
- 创建一个代理类同样实现接口;
- 将目标对象注入进代理类,在代理类中调用目标类的对应方法。
实例
1 | public static class SmsServiceProxy implements SmsService { |