一、什么是动态代理
动态代理是相对于静态代理产生的概念。
可以简单理解为,静态代理是在代码中编写好代理类,动态代理的代理类是在运行时动态生成的。
使用代理一般是为了在原类中增加一些增强功能,如Spring的AOP就是通过动态代理实现的。
二、Spring中使用动态代理
有JDK代理和CGLIB代理两种实现。
2.1 JDK代理和CGLIB代理区别
JDK
利用拦截器(拦截器必须实现InvocationHanlder)加上反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。
CJLIB
利用ASM开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。
2.2 何时选用
- 当Bean实现接口时,Spring就会用JDK的动态代理。
- 当Bean没有实现接口时,Spring使用CGlib是实现。
- 可以强制使用CGlib(在spring配置中加入<aop:aspectj-autoproxy proxy-target-class="true"/>)。
三、具体实现
3.1 JDK动态代理实现
1) 一些概念
有两个重要的类和接口InvocationHandler(接口)和Proxy(类)
InvocationHandler
InvocationHandler接口是proxy代理实例的调用处理程序实现的一个接口,业务接口的方法最终都是回调业务处理类(具体的Handler)的invoke方法完成调用
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
proxy:代理类代理的真实代理对象com.sun.proxy.$Proxy0
method:我们所要调用某个对象真实的方法的Method对象
args:指代代理对象方法传递的参数
Proxy
Proxy类就是用来创建一个代理对象的类,它提供了很多方法,但是我们最常用的是newProxyInstance方法。
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
loader:一个classloader对象,定义了由哪个classloader对象对生成的代理类进行加载
interfaces:一个interface对象数组,表示我们声明了代理类实现了这些接口,代理类就可以调用接口中声明的所有方法。
h:一个InvocationHandler对象,表示的是当动态代理对象调用方法的时候会关联到哪一个InvocationHandler对象上,并最终由其调用。
2)实现
定义一个接口:
interface Demo{
int add(int, int);
}
实现类:
class Real implements Demo {
@Override
public int add(int x, int y) {
return x + y;
}
这里Real就是我们需要代理的类。
动态代理代码:
class Handler implements InvocationHandler {
private final Real real;
public Handler(Real real) {
this.real = real;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws IllegalAccessException, IllegalArgumentException,
InvocationTargetException {
System.out.println("=== BEFORE ===");
Object re = method.invoke(real, args);
System.out.println("=== AFTER ===");
return re;
}
}
构造方法把要代理的对象传入Handler中。
这里invoke方法很重要,可以看到方法调用是通过我们传递一个Method类型参数,然后调用method.invoke来实现,即通过反射来实现。
生成代理类的样子:
public ProxyClass implements Demo {
private static Method mAdd;
private InvocationHandler handler;
static {
Class clazz = Class.forName("Demo");
mAdd = clazz.getMethod("add", int.class, int.class);
}
@Override
public int add(int x, int y) {
return (Integer)handler.invoke(this, mAdd, new Object[] {x, y});
}
}
这里add方法是调用了handler的invoke方法,传递三个参数,第一个是代理类本身,第二个是add方法的反射类,最后一个是参数列表。我们是通过InvocationHandler来完成拦截与代理。
JDK Proxy具体使用:
Handler handler = new Handler(new Real());
Demo p = (Demo)Proxy.newProxyInstance(Demo.class.getClassLoader(),
new Class[] {Demo},
handler);
p.add(1, 2);
3) 实现概述
- 定义一个Handler实现InvocationHandler接口,通过构造方法把要代理的对象传到Handler中。Handler中重写invoke方法,调用method.invoke反射实现方法原逻辑
- 通过Proxy的newProxyInstance方法创建一个代理对象
- 生成的代理类会注入InvocationHandler对象,注入Method对象,代理类方法执行需要调用handler的invoke方法,可在其中增加拦截逻辑
3.2 CGLIB动态代理实现
没有接口,直接是实现类:
class Real {
public int add(int x, int y) {
return x + y;
}
}
使用了一个与JDK Proxy中Handler类似的类:
public class Interceptor implements MethodInterceptor {
@Override
public Object intercept(Object obj,
Method method,
Object[] args,
MethodProxy proxy) throws Throwable {
System.out.println("=== BEFORE ===");
Object re = proxy.invokeSuper(obj, args);
System.out.println("=== AFTER ===");
return re;
}
}
代理类的大致样子:
public ProxyClass extends Real {
private static Method mAdd;
private static MethodProxy mAddProxy;
private MethodInterceptor interceptor;
static {
Class clazz = Class.forName("Real");
mAdd = clazz.getMethod("add", int.class, int.class);
// Some logic to generate mAddProxy.
// ...
}
@Override
public int add(int x, int y) {
return (Integer)interceptor.invoke(
this, mAdd, new Object[] {x, y}, mAddProxy);
}
}
与jdk代理大致相同,只是多了一个MethodProxy。 去上面Interceptor可以看到,调用invoke方法是
Object re = proxy.invokeSuper(obj, args);
而不是
Object re = method.invoke(obj, args);
原因是代理类继承了原始类,obj指向的就是代理类对象的实例(JDK代理中指向的是真实对象)。
如果第二种写法就会递归调用代理类的add方法。
因此cglib封装了一个MethodProxy类,其中invokeSuper方法可以调用原始基类的真正方法。
使用:
public static void main(String[] args) {
Enhancer eh = new Enhancer();
eh.setSuperclass(Real.class);
eh.setCallback(new Interceptor());
Real r = (Real)eh.create();
int result = r.add(1, 2);
}
总结
JDK代理和CGLIB代理实现本质上是很相似的。
都包含一下两点内容:
- 有一个接口或者基类,定义了一个代理类。
- 一个方法拦截器,完成方法的拦截和代理,是所有调用链的桥梁。