Java代理机制
Java代理模式
概述
代理模式是一种设计模式。简单来说就是我们使用代理对象代替对真实对象的访问,这样就可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标对象的功能
代理模式的主要作用是扩展目标对象的功能,比如说在目标对象的某个方法执行前后,你可以增加一些自定义的操作
代理模式有静态代理和动态代理两种实现方式
静态代理
静态代理中,我们对目标对象的每个方法的增强都是手动完成的,非常不灵活(比如接口一旦新增加方法,目标对象和代理对象都要进行修改)且麻烦(需要对每个目标类都单独写一个代理类)。 实际应用场景非常非常少,日常开发几乎看不到使用静态代理的场景。
静态代理实现步骤
- 定义一个接口及其实现类
- 创建一个代理类同样实现这个接口
- 将目标对象注入进代理类,然后在代理类的对应方法调用目标类中的对应方法。这样的话,我们就可以通过代理类频闭对目标对象的访问,并且可以在目标方法执行前后自定义操作
代码实例
定义支付接口
1
2
3public interface PayService{
String pay(String message);
}实现支付接口
1
2
3
4
5
6public class AliPayServiceImpl implements PayService{
public String pay(String message){
System.out.println("alipay:"+message);
}
return message;
}创建代理类并同样实现支付接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15public class PayProxy implements PayService{
private final PayService payService;
public PayService(PayService payService){
this.payService=payService;
}
public String pay(String message){
//方法执行前,自定义操作
System.out.println("before method pay()");
payService.pay(message);
//方法执行后自定义操作
System.out.println("after method pay()");
return null;
}
}实际使用
1
2
3
4
5
6
7public class Test{
public statci void main(String[] args){
payService payService=new AliPayService();
PayProxy payProxy=new PayProxy(payService);
payProxy.pay("using");
}
}
动态代理
相比于静态代理来说,动态代理更加灵活。我们不需要针对每个目标类都单独创建一个代理类,并且也不需要我们必须实现接口,我们可以直接代理实现类( CGLIB 动态代理机制)。
从 JVM 角度来说,动态代理是在运行时动态生成类字节码,并加载到 JVM 中的。
就 Java 来说,动态代理的实现方式有很多种,比如 JDK 动态代理、CGLIB 动态代理等等。
JDK动态代理
就 Java 来说,动态代理的实现方式有很多种,比如 JDK 动态代理、CGLIB 动态代理等等。
Proxy
类中使用频率最高的方法是:newProxyInstance()
,这个方法主要用来生成一个代理对象。
1 | public static Object newProxyInstance(ClassLoader loader, |
invoke()
方法有下面三个参数:
- proxy :动态生成的代理类
- method : 与代理类对象调用的方法相对应
- args : 当前 method 方法的参数
也就是说:你通过Proxy
类的 newProxyInstance()
创建的代理对象在调用方法的时候,实际会调用到实****现InvocationHandler
接口的类的 invoke()
方法。 你可以在 invoke()
方法中自定义处理逻辑。
代码实例
定义支付接口
1
2
3public interface PayService{
String pay(String message);
}实现支付接口
1
2
3
4
5
6public class AliPayServiceImpl implements PayService{
public String pay(String message){
System.out.println("alipay:"+message);
}
return message;
}自定义JDK代理类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class DebugInvocationHandler implements InvocationHandler {
/**
* 代理类中的真实对象
*/
private final Object target;
public DebugInvocationHandler(Object target) {
this.target = target;
}
public Object invoke(Object proxy, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException {
//调用方法之前,自定义操作
System.out.println("before method " + method.getName());
Object result = method.invoke(target, args);
//调用方法之后,自定义操作
System.out.println("after method " + method.getName());
return result;
}
}invoke()
方法: 当我们的动态代理对象调用原生方法的时候,最终实际上调用到的是invoke()
方法,然后invoke()
方法代替我们去调用了被代理对象的原生方法。获取代理对象的工厂类
1
2
3
4
5
6
7
8
9public class JdkProxyFactory {
public static Object getProxy(Object target) {
return Proxy.newProxyInstance(
target.getClass().getClassLoader(), // 目标类的类加载器
target.getClass().getInterfaces(), // 代理需要实现的接口,可指定多个
new DebugInvocationHandler(target) // 代理对象对应的自定义 InvocationHandler
);
}
}getProxy()
:主要通过Proxy.newProxyInstance()
方法获取某个类的代理对象使用
1
2PayService payService=(payService) JdkProxyFactory.getProxy(new AliPayService());
payService.pay("using");
CGLIB动态代理
JDK 动态代理有一个最致命的问题是其只能代理实现了接口的类,为了解决这个问题,我们可以用 CGLIB 动态代理机制来避免。
CGLIB
(Code Generation Library)是一个基于ASM
的字节码生成库,它允许我们在运行时对字节码进行修改和动态生成。CGLIB
通过继承方式实现代理。很多知名的开源框架都使用到了CGLIB
例如 Spring
中的 AOP
模块中:如果目标对象实现了接口,则默认采用 JDK
动态代理,否则采用 CGLIB
动态代理。
在 CGLIB 动态代理机制中 MethodInterceptor
接口和 Enhancer
类是核心。
你需要自定义 MethodInterceptor
并重写 intercept
方法,intercept
用于拦截增强被代理类的方法。
1 | public interface MethodInterceptor |
- obj : 被代理的对象(需要增强的对象)
- method : 被拦截的方法(需要增强的方法)
- args : 方法入参
- proxy : 用于调用原始方法
你可以通过 Enhancer
类来动态获取被代理类,当代理类调用方法的时候,实际调用的是 MethodInterceptor
中的 intercept
方法。
实现步骤
- 定义一个类;
- 自定义
MethodInterceptor
并重写intercept
方法,intercept
用于拦截增强被代理类的方法,和 JDK 动态代理中的invoke
方法类似; - 通过
Enhancer
类的create()
创建代理类;
代码示例
引入相关依赖
1
2
3
4
5<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>定义支付类
1
2
3
4
5
6public class AliPayServiceImpl {
public String pay(String message){
System.out.println("alipay:"+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
27import 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
2AliPayService aliPayService=(AliPayService)CglibProxyFactory.getProxy(AliPayService);
aliPayService.pay("using");