在前面三篇博客中,我们已经详细的讲解了有关AOP的配置文件的解析、bean的实例化,在本篇博客中我们将看到AOP是如何执行的
Dao userDao = (Dao) beanFactory.getBean("userDao");
userDao.save();
这是本篇展开的两行代码,userDao在创建的时候已经被替代成代理类了,在执行save方法的时候会被拦截被我们的AOP处理,先看一下获取userDao的流程:
public Object getBean(String name) throws BeansException {
assertBeanFactoryActive();
return getBeanFactory().getBean(name);
}
先获取IOC容器,从容器中获取bean
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
把获取bean的工作交给doGetBean方法,由于userDao已经创建好了,所以在执行下面这段代码的时候可以直接获得我们要的bean:
Object sharedInstance = getSingleton(beanName);
下面就要执行save方法了,但这已经变成代理类了,想一下,我们之前用jdk代理的时候,在执行目标类的方法时都要执行invoke方法,现在我们要执行save方法,应该也是这样:
public Object invoke(Object proxy, Method method, Object[] args)
果真,和我们想的一样,由于这个方法比较长,我们一点一点的分析:
MethodInvocation invocation;
Object oldProxy = null;
boolean setProxyContext = false;
//获得目标类
TargetSource targetSource = this.advised.targetSource;
Object target = null;
这几行主要是声明了几个对象,也没有将他们初始化
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// 目标没有实现equals(对象)方法本身。
return equals(args[0]);
}
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// 目标没有实现hashCode()方法本身。
return hashCode();
}
else if (method.getDeclaringClass() == DecoratingProxy.class) {
// 只有getDecoratedClass()声明了->分派给代理配置。
return AopProxyUtils.ultimateTargetClass(this.advised);
}
else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
// 使用代理配置对ProxyConfig的服务调用…
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
这里进行了一些判断看一下目标类能不能使用动态代理
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
得到目标类以及目标类的class对象
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
获得针对目标类并且针对当前方法的所有advisor
///看看我们是否有什么建议。如果我们不这样做,我们就可以直接依靠,目标的反射调用,避免创建方法调用。
if (chain.isEmpty()) {
// 我们可以跳过创建方法调用:直接调用目标 注意,最后的调用程序必须是InvokerInterceptor,所以我们知道它有/只有目标上的反射操作,没有热交换或花哨的代理。
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// 创建一个方法调用…
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
//通过拦截器链执行
retVal = invocation.proceed();
}
这段代码根据有没有针对当前方法的拦截器来决定是否通过创建方法调用来执行目标方法,很显然,对于我们当前要执行的方法来说需要创建方法调用,我们接下来看看程序是如何执行拦截器链的:
public Object proceed() throws Throwable {
// 判断是不是所有的拦截器都执行完了
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
//执行目标方法
return invokeJoinpoint();
}
//得到当前要执行的拦截器,并且将拦截器的记录+1
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
...
}
else {
// 执行拦截器的方法
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
这是一个递归方法,会一直执行到最后一个拦截器,判断条件是当前拦截器的索引下标,我们进去拦截器的invoke方法看一下:
public Object invoke(MethodInvocation mi) throws Throwable {
MethodInvocation oldInvocation = invocation.get();
invocation.set(mi);
try {
return mi.proceed();
}
finally {
invocation.set(oldInvocation);
}
}
这个拦截器是执行了proceed方法,但是还没有返回值的时候执行的该拦截器的处理,这应该是对目标方法执行后起作用的,再继续看下一个拦截器:
public Object invoke(MethodInvocation mi) throws Throwable {
try {
return mi.proceed();
}
finally {
invokeAdviceMethod(getJoinPointMatch(), null, null);
}
}
这是一个后置拦截器,也是要在目标方法执行后才执行这个拦截器,下一个拦截器:
public Object invoke(MethodInvocation mi) throws Throwable {
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );
return mi.proceed();
}
这次不一样了,先执行了这个拦截器的逻辑才继续遍历下一个拦截器,这一定是前置拦截器了,看一下这个拦截器的类的名字是MethodBeforeAdviceInterceptor,和我们想的一样,果然执行完逻辑之后得到了我们想要的效果:
这已经是最后一个拦截器了,之后就要执行目标方法了:
protected Object invokeJoinpoint() throws Throwable {
return AopUtils.invokeJoinpointUsingReflection(this.target, this.method, this.arguments);
}
通过反射的方式调用目标方法,也得到了我们想看到的效果:
现在要返回去执行后置拦截器了:
invokeAdviceMethod(getJoinPointMatch(), null, null);
这是要执行AspectJAfterAdvice的逻辑,和我们想的效果是一样的:
retVal = invocation.proceed();
最后得到执行完save方法之后的返回值。执行流程还是很简单的,到下一篇我们就要看看Spring是如何处理事务的。