本文主要是以xml配置的形式来讲解Spring AOP的整个思想与处理过程,Spring AOP的整个过程其实是与IOC的初始化紧密的结合在一起的。大家在看本文之前最好看一看博主之前写的两篇文章,Spring AOP Concepts 和 Spring Extensible XML 这两篇文章。最开始本来想直接写这篇文章的,怕写了大家看了迷惑。就写了前两篇给大家入门。
注意:本文旨在告诉大家AOP的整个过程,很多细节都没有展开,大家有兴趣可以依次展开。
其实Spring AOP的整个过程可以分为三步:
- 解析xml配置创建Advise,Aspect,Advisor和Join point对象。
- IOC初始化过程中,根据策略创建代理对象以及代理配置信息Advised。
- 方法调用,找到生成代理对象与配置信息进行代理调用
1、解析xml
在解析xml配置的时候,会隐式的注册AspectJAwareAdvisorAutoProxyCreator,这个BeanPostProcessor,关于BeanPostProcess这个对象如果大家不熟悉可以查看之前的blog – Spring Container Extension,通知Spring可能需要创建代理对象,并且创建Advise,Aspect和Advisor对象。
1) 注册AspectJAwareAdvisorAutoProxyCreator
下面是Spring AOP注册AspectJAwareAdvisorAutoProxyCreator的时序图:
在解析XML的时候会把AspectJAwareAdvisorAutoProxyCreator以BeanDefinitioin的形式注册到Spring容器中,依赖注入的时候会把它解析。
2) 解析XML,生成代理需要的对象
使用AopNamespaceHandler中的ConfigBeanDefinitionParser解析配置文件中的Aspect,Pointcut,Advice。注意这里创建的都是BeanDefinition对象,而不是我们真正需要的对象,Spring最终创建对象都是在依赖注入的步骤。也就是由BeanFactory.getBean()方法触发。
- Aspect:你想对于目标方法进行增强的方法对应的类,使用SimpleBeanFactoryAwareAspectInstanceFactory创建。
- Pointcut:切入点,在xml里面一般使用AspectJExpressionPointcut。
Advice:通知,你对切入点需要增强的类型,Spring支持以下类型。
1)Before advice,前置通知,在方法执行前执行
2)After returning advice,在方法正常执行之后执行(不包含异常)
3)After throwing advice, 在方法执行的时候包含异常的通知
4)After (finally) advice,不管执行方法是否正常执行,都会后置的通知
5)Around advice,环绕通知。
Advice这个对象创建的时候是使用spring ioc当中的构造器来创建:
具体调用位置:
org.springframework.aop.config.ConfigBeanDefinitionParser#createAdviceDefinition
index[0] = METHOD_INDEX,增强的方法,也就是通知对应的方法。(doBefore()),Spring使用MethodLocatingFactoryBean类。
index[1] = POINTCUT_INDEX,AOP作用到的具体方法,就是切点,需要增强的方法。Spring根据配置找到对应的通知类。
index[2] = ASPECT_INSTANCE_FACTORY_INDEX, 切面实例,持有通知对应方法(也就是index[0]),对应的类。Spring使用SimpleBeanFactoryAwareAspectInstanceFactory类。
e.g.
- AspectJMethodBeforeAdvice(Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif);
- AspectJAfterAdvice(Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif);
Advisor:默认使用PointcutAdvisor接口(xml配置中具体使用AspectJPointcutAdvisor),它持有Pointcut和Advice对象。
每生成一个Advice都会生成一个对应的Advisor对象,然后Advisor可以根据这个Advice生成相应的advice与pointcut属性。
2、生成代理对象
在讲解生成代理对象之前先给大家阐述一下里面需要使用到的概念:
- Advised 这个一个接口用于持有AOP动态代理的配置,这个配置包含Interceptors和advice,Advisor以及代理的接口
注意:这里的Advisor也就是通知,包含这个实现类的所有通知,这个在真正方法调用的时候将会把这个找到真正match的Advisor.再进行调用。 - AopProxyFactory 生成AopProxy基于AdvisedSupport的配置对象,分为JDK动态代理(JdkDynamicAopProxy)与Cglib动态代理(ObjenesisCglibAopProxy)
- ProxyFactory 生成代理对象工厂类,用于生成代理对象
以JDK动态代理为例:
final class JdkDynamicAopProxy implements AopProxy,InvocationHandler, Serializable{
@Override
public Object getProxy() {
// 获取代理对象
}
@Override
public Object getProxy(ClassLoader classLoader) {
// 获取代理对象
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 代理对象调用方法
}
}
从上面这个类我们可以得出以后的结论:
- 实现AopProxy,所有具有获取Proxy代理对象的能力。
- 实现InvocationHandler,具有了创建动态代理的能力。
- 持有AdvisedSupport类,这个类是实现了Advised接口了,所以它获取动态代理类里面的配置功能。
整个代理对象创建的触发是AspectJAwareAdvisorAutoProxyCreator的父类:AbstractAutoProxyCreator
下面就大概说一下每一步的作用:
- 第一步,入口方法
- 第二步,判断这个对象是否需要被代理
- 第三步是找到匹配当前目标类的所有Advisor(还得上面所说的吗?这个Advisor其实使用的是PointcutAdvisor,包含Pointcut与Advise信息)
- 第四步,获取到代理对象,并且Spring AOP会为代理对象创建Advised对象其实也就是ProxyFactory,用于代理调用时使用。
3、方法调用
这里以JdkDynamicAopProxy这个生成的代理类为例。我们都知道JDK动态代理最后调用方法会调用InvocationHandler的invoke方法。而我们就可以看看JdkDynamicAopProxy这个类的invoke方法到底干了哪些事:
JdkDynamicAopProxy#invoke
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MethodInvocation invocation;
Object oldProxy = null;
boolean setProxyContext = false;
TargetSource targetSource = this.advised.targetSource;
Class<?> targetClass = null;
Object target = null;
try {
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
return equals(args[0]);
}
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
return hashCode();
}
else if (method.getDeclaringClass() == DecoratingProxy.class) {
return AopProxyUtils.ultimateTargetClass(this.advised);
}
else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
Object retVal;
if (this.advised.exposeProxy) {
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
target = targetSource.getTarget();
if (target != null) {
targetClass = target.getClass();
}
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
if (chain.isEmpty()) {fancy proxying.
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();
}
Class<?> returnType = method.getReturnType();
if (retVal != null && retVal == target &&
returnType != Object.class && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
retVal = proxy;
}
else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
throw new AopInvocationException(
"Null return value from advice does not match primitive return type for: " + method);
}
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
// Must have come from TargetSource.
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
1、使用上一步生成的Advised对象根据方法与目标对象获取拦截器chain.
这样就把AOP里面的Advise与方法结合了起来。
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
2、判断拦截器chain是否为空
1)空执行原来方法
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
这个方法就是通过反射调用方法,没有什么可讲的。
2)不为空,执行拦截器chain.
创建ReflectiveMethodInvocation对象调用proceed方法。
ReflectiveMethodInvocation#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();
}
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);
}
}
从这个方法中我们可以看到,会依次遍历拦截器链,然后使用proceed()这个方法递归调用来拦截器来。这样就达到了AOP的功能。