AOP
1. 实现植入代码的链式调用。
上一节的学习中。通过读取aop的配置文件已经实例化了一个Pointcut(AspectJExpressionPointcut),它被用来找到那些满足被植入条件的Method。以及MethodLocatingFactory,它被用来定位具体的切入Method(注意,这里的Method,不是Pointcut中的target method,而是具体植入代码的方法)。
接下来很自然的就会想到,将MethodLocatingFactory中定位到的植入代码的Method与pointcut中找到的那些满足被植入条件的method结合起来,希望达到的效果是当我调用被植入method的时候,在执行它的之前、之后做一些具体的操作。
植入代码的Method在AOP中是以MethodInterceptor的理念被实现的。在AOP alliance中,MethodInterceptor接口继承了Interceptor,进而Interceptor又继承了Advice。Advice仅仅是个空接口,仅表示实现了它的都是属于它Advice这个class。这样就很好理解了,在执行目标代码的时候,有什么对它要说的建议都要实现上述的接口。
上述图中具体的AspectJAfterReturnAdvice中包含了adviceMethod(具体植入代码的方法),pointcut,以及adviceObjectFatory(它来提供被植入代码的方法所属类的信息)。
接下来需要一个调度类来结合被植入的MethodInterceptor和目标方法。Spring AOP中使用了ReflectiveMethodInvocation。如下图所示,ReflectiveMethodInvocation其实就是一个Jointpoint,实现了proceed方法,这是植入代码链式调用的核心,所以,没错ReflectiveMethodInvocation封装了一系列的MethodInterceptor。同时,ReflectiveMethodInvocation封装了目标方法,和目标类型,当然他们使用来调用原本的方法的。
接下来看看ReflectiveMethodInvocation的核心方法,Proceed(),它实现自Jointpoint接口。在方法中,遍历地查看MethodInterceptor,然后调用interceptor的invoke方法,具体的AfterReturning, AfterThrowing, BeforeAdvice的方法就在这其中实现。调用invoke的同事,ReflectiveMethodInvocation会将自己作为参数传入,这样就实现了链式调用。其实结合起来看,ReflectiveMethodInvocation作为Jointpoint,它包含了目标方法,目标类型,目标方法参数以及拦截器
到此已经完成了advice注入jointpoint的链式调用。那么下一步,就是剩下动态得生成AOP proxy对象了。达到的效果就是,当调用某类的方法时候,调用的是他的子类即proxy类的方法。proxy类包含了一些列advices,目标方法,目标类型。Spring AOP中定义了,如下的AopProxyFactory创建proxy类。如图所示,得到一个proxy类,我们只需要给出相应的Advice(即Interceptor)和targetObject(即rootClass, proxy类继承于它)。CglibProxyFactory在实现AopProxyFactory接口方法getProxy时,会设置好Callback(Cglib中的Interceptor),callBack中通过AOPConfig中的advice的属性中的AspectJExpressionPointcut(上一章一开始实现的类,在这用到了)来匹配目标的Method。若匹配得上,则将advice加入Interceptor。
Callback[] callbacks = getCallbacks(rootClass);
private Callback[] getCallbacks(Class<?> rootClass) throws Exception {
Callback aopInterceptor = new DynamicAdvisedInterceptor(this.config);
//Callback targetInterceptor = new StaticUnadvisedExposedInterceptor(this.advised.getTargetObject());
//Callback targetDispatcher = new StaticDispatcher(this.advised.getTargetObject());
Callback[] callbacks = new Callback[] {
aopInterceptor, // AOP_PROXY for normal advice
/*targetInterceptor, // INVOKE_TARGET invoke target without considering advice, if optimized
new SerializableNoOp(), // NO_OVERRIDE no override for methods mapped to this
targetDispatcher, //DISPATCH_TARGET
this.advisedDispatcher, //DISPATCH_ADVISED
new EqualsInterceptor(this.advised),
new HashCodeInterceptor(this.advised)*/
};
return callbacks;
}
private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable {
private final AopConfig config;
public DynamicAdvisedInterceptor(AopConfig advised) {
this.config = advised;
}
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object target = this.config.getTargetObject();
List<Advice> chain = this.config.getAdvices(method/*, targetClass*/); // 通过在运行时调用匹配的Method
Object retVal;
// Check whether we only have one InvokerInterceptor: that is,
// no real advice, but just reflective invocation of the target.
if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
// We can skip creating a MethodInvocation: just invoke the target directly.
// Note that the final invoker must be an InvokerInterceptor, so we know
// it does nothing but a reflective operation on the target, and no hot
// swapping or fancy proxying.
retVal = methodProxy.invoke(target, args);
}
// 有匹配上的方法,拦截器不为空。
else {
List<org.aopalliance.intercept.MethodInterceptor> interceptors =
new ArrayList<org.aopalliance.intercept.MethodInterceptor>();
interceptors.addAll(chain);
// We need to create a method invocation...
retVal = new ReflectiveMethodInvocation(target, method, args, interceptors).proceed();
}
//retVal = processReturnType(proxy, target, method, retVal);
return retVal;
}
}
- 最终在运行时调用方法时,会触发拦截器的匹配,然后对有匹配到的方法进行拦截,用ReflectiveMethodInvocation(即Jointpoint)。