Spring AOP使用两种代理机制:基于JDK的动态代理;基于CGLIB的动态代理。之所以需要两种,是因为JDK本身只提供接口的代理,不支持类的代理。
JDK动态代理:java.lang.reflect包下的Proxy, InvocationHandler
1.编写一个handler类实现InvocationHandler接口,invoke方法:
public Object invoke(Object target, Method method, Object[] args) throws Throwable {
//代理前逻辑
Object obj = methos.invoke(target, args);
//代理后逻辑
return obj;
}
2.调用Proxy,
Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), handler);//三个参数classLoader, interfaces, 实现invocationHandler的类
GCLib动态代理:JDK的限制:只能为接口创建代理实例.
CGLib采用非常底层的字节码技术,可以为一个类创建子类,并在子类中采用方法拦截技术拦截所有父类方法的调用,并顺势织入横切逻辑。
1、创建一个CGLibProxy实现MethodInterceptor
package com.billkang;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class CGLibProxy implements MethodInterceptor {
private Enhancer enhancer = new Enhancer();
public Object getProxy(Class clazz) {
enhancer.setSuperclass(clazz); //设置需要创建子类的类
enhancer.setCallback(this);
return enhancer.create(); //通过字节码技术动态创建子类实例
}
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
System.out.println("代理前逻辑");
Object result = proxy.invokeSuper(obj, args);
System.out.println("代理后逻辑");
return result;
}
}
2、应用的时候 ForumServiceImpl service = (
ForumServiceImpl)
cgLibProxy.getProxy(ForumServcieImpl.class);
由于CGlib采用动态创建子类的方式生成代理对象,所以不能对目标类中的final、private方法进行代理。
对于singleton的代理,推荐使用CGlib,对于其他作用域的代理,最好使用JDK,因为CGlib创建代理的时候慢,而创建出的代理对象运动效率极高,而使用JDK代理的表现刚好相反。