最近几天看了Spring aop部分的源码,刚开始是看书的,那本业界还挺有名气的Spring技术内幕,但是看了好久也没看出个大概来,还总是忘。昨天决定用eclipse调试的功能来跟踪源码。到现在为止,脉络已经算比较清楚了。现总结如下:
先看几个名词术语
1.pointcut:切点,目标方法的范围,就是说那些方法需要被增强
2.advice:通知,具体需要增强的方法,就是说需要为目标方法怎么增强
3.joinpoint:目标方法,执行目标对象的方法
其他名词不需要过多解释
其实这个过程大致分为以下几步:
1.生成代理对象,需要清楚,增强方法的执行都是代理对象在执行的,这样就与目标对象解耦开来,具体怎么生成代理对象,无外乎动态代理和cglib两种方式。
2.生成代理对象之后,当目标方法被执行的时候,JdkDynamicAopProxy的invoke()方法就被执行,因为这个类实现了InvocationHandler接口,所以当目标对象的所有方法被调用的时候都会在invoke()方法里面被拦截。拦截后怎么做呢?针对每个方法,生成拦截器!具体是怎么生成的呢?经过跟踪源码,发现,每个方法都会生成针对于这个方法的拦截器。当然,步骤是,先读取配置中的所有Advisor,遍历每个Advisor,如果匹配当前方法,则将这个Advisor封装为拦截器添加到当前方法的拦截器链中,然后,依次执行这个拦截器链。这个拦截器链是ReflectiveMethodInvocation这个类调用的,调用方法为proceed(),在这个方法中,依次遍历每个拦截器,在拦截器中回调proceed()方法,又用到了回调!!!当拦截器执行完后,调用目标对象的方法。好了,那么是如何将advice织入的呢?在拦截器的invoke()方法中,比如是前置通知,则先执行通知,再调用proceed()方法,类似的。。。最终,实现了通知的织入。
补充:
其实这个拦截器和struts2的拦截器机制是相同的,struts2是通过actionInvocation里面调用拦截器的invoke()方法的,而拦截器的invoke()方法里面继续回调invocation()里面的intercept()方法的
补充2:重新跟踪了一遍源码:Spring的Aop机制是这样的:首先,会在配置文件中配置拦截器,可以配置多个拦截器,也可以不配置拦截器,spring会为每个真实对象都生成一个代理对象,所以当执行目标方法时,会自动被代理对象的invoke()方法所拦截。进入invoke方法的执行流程中,这里截取部分代码
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MethodInvocation invocation = null;
Object oldProxy = null;
boolean setProxyContext = false;
TargetSource targetSource = this.advised.targetSource;
Class targetClass = null;
Object target = null;
try {
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// The target does not implement the equals(Object) method itself.
return (equals(args[0]) ? Boolean.TRUE : Boolean.FALSE);
}
if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// The target does not implement the hashCode() method itself.
return new Integer(hashCode());
}
if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
// Service invocations on ProxyConfig with the proxy config...
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
Object retVal = null;
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// May be <code>null</code>. Get as late as possible to minimize the time we "own" the target,
// in case it comes from a pool.
target = targetSource.getTarget();
if (target != null) {
targetClass = target.getClass();
}
// Get the interception chain for this method.
List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);//这里是获取拦截器链的过程,也就是获取
//配置文件中的拦截器的过程,在这个过程中,会将文件中的拦截器一个个加入到链中,并已经封装了通知类型,这个顺序应该是根据配置文件中的
//配置顺序加入的,但是,后置通知好像是反着加入的!!因为后置通知的执行顺序是反的,这样可以刚好按照配置顺序执行
// Check whether we have any advice. If we don't, we can fallback on direct
// reflective invocation of the target, and avoid creating a MethodInvocation.
if (chain.isEmpty()) {
// 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 = AopUtils.invokeJoinpointUsingReflection(target, method, args);
}
else {
// We need to create a method invocation...
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// Proceed to the joinpoint through the interceptor chain.
retVal = invocation.proceed();//这是个重点,不断的回调拦截器链来执行增强方法
}
看下面proceed()方法的执行:
public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();//当前拦截器为空时,执行目标方法,即是Joinpoint()方法
}
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
// Evaluate dynamic method matcher here: static part will already have
// been evaluated and found to match.
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
// Dynamic matching failed.
// Skip this interceptor and invoke the next in the chain.
return proceed();
}
}
else {
// It's an interceptor, so we just invoke it: The pointcut will have
// been evaluated statically before this object was constructed.
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);//可以认为跳到这个方法,就是执行具体拦截器的方法
}
}
第一个执行的拦截器是ExposeInvocationInterceptor,其实里面就是继续回调
public Object invoke(MethodInvocation mi) throws Throwable {
Object old = invocation.get();
invocation.set(mi);
try {
return mi.proceed();
}
finally {
invocation.set(old);
}
}
如果是个前置通知,代码是这样的:
public Object invoke(MethodInvocation mi) throws Throwable {
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );//这个就是执行的核心方法,先执行前置方法,然后继续回调!
return mi.proceed();
}
如果是个后置通知,代码是这样的:
public Object invoke(MethodInvocation mi) throws Throwable {
try {
return mi.proceed();//先继续回调,
}
finally {
invokeAdviceMethod(getJoinPointMatch(), null, null);//最终执行后置通知,注意,最终执行的顺序是反向的,类似于栈,不断的回调递归,
//所以,后置通知执行顺序相反,但是假如拦截器链顺序如果反向,结果还是顺序执行
}
}