Spring AOP的底层是基于JDK和CGLIB代理技术来实现的,要理解Spring AOP,需要先对JDK和CGLIB有一定的认识和理解。
一. JDK动态代理
先看一段Demo示例,首先定义一个接口:
public interface DemoInterface {
public void service();
}
该接口的实现:
public class DemoImpl implements DemoInterface {
@Override
public void service() {
System.out.println("do service");
}
}
定义一个InvocationHandler的实现类:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class DemoInvocationHandler implements InvocationHandler {
private Object obj;
public DemoInvocationHandler(Object obj) {
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Start.");
Object result = method.invoke(obj, args);
System.out.println("End.");
return result;
}
}
看看效果:
import java.lang.reflect.Proxy;
public class Main {
public static void main(String[] args) {
DemoImpl demoImpl = new DemoImpl();
DemoInterface demoInterface = (DemoInterface) Proxy.newProxyInstance(demoImpl.getClass()
.getClassLoader(), demoImpl.getClass().getInterfaces(),
new DemoInvocationHandler(demoImpl));
demoInterface.service();
System.out.println(demoInterface.getClass());
}
}
控制台输出:
可见这个代理类已经按我们的设计工作了,最后一个输出是代理类的Class Name,可以看到是class com.sun.proxy. Proxy0,这个就是所谓的动态代理,“动态“生成了一个新类,新类名字叫 Proxy0。
接下来探秘一下这个动态代理是如何实现的,进入Proxy.newProxyInstance()函数看看源码,比较关键的是这句:
这里生成了代理类的Class对象,跟进这个方法,会跟进到Proxy类里面的内部类ProxyClassFactory里面的apply方法中,关键片段是这里:
先看这个ProxyGenerator.generateProxyClass(proxyName, interfaces, accessFlags),源码:
可以看出来这实际在根据一些信息直接生成class的byte[]数组,就是前面所说的 com.sun.proxy.$Proxy0.class(有兴趣可以展开localProxyGenerator.generateClassFile()看看如何生成的class文件)。
ProxyClassFactory里面的apply方法中的另一个关键方法是defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length);,看看源码:
已经是一个native方法了,作用就是把class文件加载进来。
可以看出,com.sun.proxy.$Proxy0实际上是JDK根据既定规则直接生成class文件,然后像加载其他class文件一样加载进来,这就动态生成了一个类。
理解了代理类的动态生成,还有一个关键点是代理类如果跟InvocationHandler实现方法调用的拦截,回到Proxy.newProxyInstance()函数的最后一行:
可见InvocationHandler是作为构造函数的参数被传入的,可以理解,其实在生成com.sun.proxy. Proxy0,已经为com.sun.proxy. Proxy0定义了规则,使其接受InvocationHandler是作为构造函数的参数。
二. CGLIB动态代理
搞清楚JDK动态代理后,再看看CGLIB动态代理。从上面可以看出,JDK动态代理是需要一个接口和相应实现类的,如果没有接口,只有实现类,JDK动态代理就没法创建代理对象了,这个时候需要CGLIB动态代理。
先看一段Demo示例
被代理类:
public class DemoClass {
public void service() {
System.out.println("do service");
}
}
InvocationHandler的实现类:
import java.lang.reflect.Method;
import net.sf.cglib.proxy.InvocationHandler;
public class DemoInvocationHandler implements InvocationHandler {
private Object obj;
public DemoInvocationHandler(Object obj) {
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Start.");
Object result = method.invoke(obj, args);
System.out.println("End.");
return result;
}
}
跟jdk动态代理的InvocationHandler基本一样,不过要注意这里是net.sf.cglib.proxy.InvocationHandler接口。
最后看看Main类:
import net.sf.cglib.proxy.Enhancer;
public class Main {
public static void main(String[] args) {
DemoClass demoClass = new DemoClass();
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(DemoClass.class);
enhancer.setCallback(new DemoInvocationHandler(demoClass));
DemoClass proxy = (DemoClass) enhancer.create();
proxy.service();
System.out.println(proxy.getClass());
}
}
输出结果如下:
可见代理已经正确工作了,并且生成了一个动态代理类:com.liuxiang.j2se.jdemo.proxy.cglib.demo.DemoClass
EnhancerByCGLIB 1b87eda0
CGLIB的原理和JDK动态代理的原理基本差不多(当然代码实现上差别很大),都是根据规则动态生成代理类class的byte[]数组,然后使用classLoader进行加载,有兴趣可以去看看源代码一探究竟。
三. ProxyFactory
Spring AOP在底层同时使用JDK,CGLIB动态代理技术,默认情况下,对实现了接口的类使用JDK代理,对没有实现接口的类使用CGLIB代理,实际也可以用参数进行控制。
另外,无论JDK动态代理,还是CGLIB动态代理,都需要实现一个InvocationHandler接口,显然这个接口更贴近代理机制本身,跟AOP机制那些概念相去甚远。
所以Spring实现了ProxyFactory,封装了底层的JDK,CGLIB代理技术(以及选择哪种代理技术),封装了AOP的通知Advice到InvocationHandler的转化。
看下Demo程序
一个接口:
public interface Pojo {
public void foo();
}
接口的实现类SimplePojo:
public class SimplePojo implements Pojo {
@Override
public void foo() {
System.out.println("SimplePojo.foo");
}
}
一个相似的类SimplePojoNoInterface,但没有实现任何接口:
public class SimplePojoNoInterface {
public void foo() {
System.out.println("SimplePojoNoInterface.foo");
}
}
新建一个BeforeAdvice:
import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;
public class DemoAdvice implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("before advice");
}
}
然后使用ProxyFactory分别为其生成代理:
import org.springframework.aop.framework.ProxyFactory;
public class Main {
public static void main(String[] args) {
ProxyFactory factory = new ProxyFactory(new SimplePojo());
factory.addInterface(Pojo.class);
factory.addAdvice(new DemoAdvice());
Pojo pojo = (Pojo) factory.getProxy();
ProxyFactory factory2 = new ProxyFactory(new SimplePojoNoInterface());
factory2.addAdvice(new DemoAdvice());
SimplePojoNoInterface simplePojoNoInterface = (SimplePojoNoInterface) factory2.getProxy();
pojo.foo();
System.out.println(pojo.getClass());
simplePojoNoInterface.foo();
System.out.println(simplePojoNoInterface.getClass());
}
}
运行结果如下:
可见ProxyFactory为有接口的SimplePojo生成了JDK动态代理,为没有接口的SimplePojoNoInterface生成了CGLIB动态代理,并且都成功织入了DemoAdvice。
看看DefaultAopProxyFactory的createAopProxy方法:
可以看到这里就是选择使用JDK代理还是CGLIB代理。
JdkDynamicAopProxy(config);是对JDK动态代理的封装,在参数config中包含了advice信息,在JdkDynamicAopProxy里面会实现advice向InvocationHandler的转换,JdkDynamicAopProxy本身就是InvocationHandler的实现类,看看invoke方法的关键片段:
可以看出来这里其实是生成了一个方法调用链,来织入多个Advice。
再看看CglibAopProxy的实现:
可见Enhancer本身支持设置多个callback,所以CGLIB的实现要相对简洁一点