JDK
Spring aop默认使用jdk动态代理。
jdk动态代理要求被代理对象是某个接口的实现类。为什么呢,先看一个简单的例子
//一个接口
public interface FoodService {
void makeNoddles();
void makeChicken();
}
//被代理对象的类(实现了接口)
public class FoodServiceImpl implements FoodService{
@Override
public void makeChicken() {
System.out.println("chicken");
}
@Override
public void makeNoddles() {
System.out.println("noddles");
}
}
//真正要写的类,实现JDK提供的InvocationHandler接口
public class ProxyFactory implements InvocationHandler {
//被代理对象
private Object target;
//构造器
public ProxyFactory(Object target){
this.target=target;
}
//创建代理对象Proxy
public Object createProxy(){
ClassLoader classLoader=target.getClass().getClassLoader();
//获取被代理对象所属类实现的接口
Class<?>[] interfaces=target.getClass().getInterfaces();
//从源码上看,newProxyInstance()这个方法必须要interfaces参数
Object proxyInstance=Proxy.newProxyInstance(classLoader,interfaces,this);
return proxyInstance;
}
//必须重写invoke方法,可以在方法执行前后增加处理逻辑
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before");
Object invoke=method.invoke(target,args);
System.out.println("after");
return invoke;
}}
//测试类
public class Test {
public static void main(String[] args) {
//被代理对象
FoodServiceImpl f=new FoodServiceImpl();
//传入被代理对象,创建工厂
ProxyFactory proxyFactory=new ProxyFactory(f);
//创建代理对象并转为被代理对象的接口类型
FoodService foodService=(FoodService) proxyFactory.createProxy();
//代理对象执行原方法,内部自动调用了ProxyFactory的invoke方法,实现了动态代理
foodService.makeNoddles();
}
}
从代码来看,jdk提供的动态代理使用比较简单,真正需要写的代码就是上面的ProxyFactory类,实现InvocationHandler并重写invoke方法就行,之所以要求被代理类有借口,因为本身设计是基于接口实现的,需要依靠接口创建代理对象。
public final class $Proxy0 extends Proxy implements HelloInterface{
.......
JDK动态代理动态生成的代理类,已经继承了Proxy,因为JAVA单继承,要获得被代理类的特性只能从实现接口的角度。
cglib
cglib基于第三方框架,采用字节码技术实现动态代理
public class CglibProxyFactory implements MethodInterceptor {
private Object target;
public CglibProxyFactory(Object target){
this.target=target;
}
public Object createProxy(){
Enhancer enhancer=new Enhancer();
//传参 被代理类
enhancer.setSuperclass(target.getClass());
enhancer.setCallback(this);
//返回代理对象
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("cglib before");
Object invoke= methodProxy.invoke(target,objects);
System.out.println("cglib after");
return invoke;
}
public static void main(String[] args) {
FoodServiceImpl f=new FoodServiceImpl();
CglibProxyFactory factory=new CglibProxyFactory(f);
FoodServiceImpl foodService=(FoodServiceImpl) factory.createProxy();
foodService.makeChicken();
}
}
cglib动态代理创建代理对象只需要被代理类,不受接口限制,
因为在底层,cglib实现动态代理是在运行时依据字节码,动态生成被代理类的子类,并在子类中对原方法进行增强。是从继承的角度实现动态代理(所以被代理类不能被final,private修饰)。
效率
二者效率对比,从JDK1.8开始,JDK的动态代理执行速度要比cglib高,但是JDK动态代理有一定限制,就是被代理对象必须要有接口。而cglib适用任何情况。