其实AOP就是一个复杂动态代理的实现,只不过它融合了拦截器,利用了IoC功能。
动态代理是代理模式动态实现的方式,其中代理类是由JDK动态生成的,具体可见http://www.cnblogs.com/gonjan-blog/p/6685611.html
我们下面简单说明一下动态代理对象的创建步骤:
// 创建一个InvocationHandler对象(与代理类相关联),Person为接口Stu为目标对象
InvocationHandler = stuHandler = new MyInvocationHandler<person>(stu);
// 使用Proxy类的getProxyClass静态方法生成一个动态代理类stuProxyClass.
Class<?> stuProxyClass = Proxy.getProxyClass(Person.class.getClassLoader(), new Class<?>[] {Person.class});
// 获得stuProxyClass中一个带InvocationHandler参数的构造器
Constructor<?> constructor = PersonProxy.getConstructor(InvocationHandler.class);
// 通过构造器constructor来创建一个动态实例stuProxy
Person stuProxy = (Person) cons.newInstance(stuHandler);
一个动态代理对象就创建完毕,当然,上面四个步骤可以通过Proxy类的newProxyInstances方法来简化:
//创建一个与代理对象相关联的InvocationHandler
InvocationHandler stuHandler = new MyInvocationHandler<Person>(stu);
//创建一个代理对象stuProxy,代理对象的每个执行方法都会替换执行Invocation中的invoke方法
Person stuProxy= (Person) Proxy.newProxyInstance(Person.class.getClassLoader(), new Class<?>[]{Person.class}, stuHandler);
原理如下:jdk为我们的生成了一个叫$Proxy0(这个名字后面的0是编号,有多个代理类会一次递增)的代理类,这个类文件时放在内存中的,我们在创建代理对象时,就是通过反射获得这个类的构造方法,然后创建的代理实例。
可以对InvocationHandler看做一个中介类,中介类持有一个被代理对象,在invoke方法中调用了被代理对象的相应方法。通过聚合方式持有被代理对象的引用,把外部对invoke的调用最终都转为对被代理对象的调用。
理解了动态代理的实现原理,下面正式进入AOP。
首先,spring通过ProxyFactoryBean实现AOP功能的第一步,得到AopProxy代理对象(通过使用JDK或CGLIB最终产生AopProxy代理对象)。然后,再通过AopProxy代理对象的拦截机制实现AOP功能。
具体流程如下:
ProxyFactoryBean中的入口方法getObject():
initializeAdvisorChain():
初始化通知链,通过读取配置中的interceptorNames属性进行配置,并提供getBean()向IoC容器获取通知器,
然后将通知器加入拦截器中。
根据singleton和prototype来生成对应的proxy。
getSingletonInstance()
读取ProxyFactoryBean中的配置,为生成代理对象做好准备。
getProxy(createAopProxy())
实际是通过createAopProxy返回的对象来得到代理对象。
createAopProxy()
通过AopProxyFactory取得AopProxy,默认使用DefaultAopProxyFactory
createAopProxy(AdvisedSupport config)
其中再AdvisedSupport中封装了生成具体代理对象所需要的所有信息
通过判断targetClass 是否接口类型来选择使用jdk还是CGLIB来生成Proxy
下面具体说一下具体JDK生成Proxy的过程(充分利用了动态代理)。
Proxy.newProxyInstance():
其中有一个参数为InvocationHandler,这个接口定义了invoke()方法,而当proxy对象的代理方法被调用时,JDKDynamicAop
的invoke方法将作为Proxy对象的回调函数被触发。从而通过Invoke方法的据欸实现来完成对目标对象方法调用的拦截或增强工作。
invoke():
// 得到目标对象
target = targetSource.getTarget();
// 通过AdvisedSupport取得拦截器链
LIst<Object> chain = this.advised.getInterceptordAndDynamicInterceptionAdvice(method,targetClass);
// 为目标对象创建回调方法,需要再调用通知后再调用目标对象的方法
invocation = new ReflectMethodInvocation()
// 沿着拦截器链继续前进,这里完成对目标对象的增强
retcal = invocation.proceed();