Spring AOP拦截器调用的实现
设计原理
在SpringAOP通过JDK的Proxy方式或CGLIB方式生成代理对象的时候,相关的拦截器已经配置到代理对象中去了,拦截器在代理对象中起作用是通过对这些方法的回调来完成的。如果使用JDK的Proxy来生成代理对象,那么需要通过InvocationHandler来设置拦截器回调,而如果使用CGLIB来生成代理对象,就需要根据CGLIB的使用要求,通过DynamicAdvisedInterceptor来完成回调。关于这两种方式的拦截过程,下面我们会进行详细的分析。
JdkDynamicAopProxy的invoke拦截
前面介绍了在Spring中通过ProxyFactoryBean实现AOP功能的第一步,得到AopProxy代理对象的基本过程,以及通过使用JDK和CGLIB最终产生AopProxy代理对象的实现原理。下面来看看AopProxy代理对象的拦截机制是怎样发挥作用和实现AOP功能的。在JdkDynamicAopProxy中生成Proxy对象时,我们回顾一下它的AopProxy代理对象的生成调用,如下所示:
javascript
Proxy.newProxyInstance(classLoader, proxiedInterface, this);
这里的this参数对应的是InvocationHandler对象,InvocationHandler是JDK定义的反射类的一个接口,这个接口定义了invoke方法,而这个invoke方法是作为JDKProxy代理对象进行拦截的回调人口出现的。在JdkDynamicAopProxy中实现了InvocationHandler接口,也就是说当Proxy对象的代理方法被调用时,JdkDynamicAopProxy的invoke方法作为Proxy对象的回调函数被触发,从而通过invoke的具体实现,来完成对自标对象方法调用的拦截或者说功能增强的工作。JakDynamicAopProxy的invoke方法实现如下代码清单所示。从代码清单中可以看到,对Proxy对象的代理设置是在invoke方法中完成的,这些设置包括获取自标对象、拦截器链,同时把这些对象作为输入,创建了ReflectiveMethodinvocation对象,通过这个ReflectiveMethodInvocation对象来完成对AOP功能实现的封装。在这个invoke方法中,包含了一个完整的拦截器链对自标对象的拦截过程,比如获得拦截器链并对挡截器链中的拦截器进行配置,逐个运行拦截器链重的拦截增强,直到最后对自标对象方法的运行等。
org.springframework.aop.framework.JdkDynamicAopProxy#invoke的实现如下:
kotlin
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
TargetSource targetSource = this.advised.targetSource;
Object target = null;
try {
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// The target does not implement the equals(Object) method itself.
// 如果目标对象没有实现Object类的基本方法equals,直接返回基类的equals方法的调用
return equals(args[0]);
}
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// The target does not implement the hashCode() method itself.
// 如果目标对象没有实现Object类的基本方法hashCode,并且调用了hashCode方法,直接返回基类的hashCode方法的调用
return hashCode();
}
else if (method.getDeclaringClass() == DecoratingProxy.class) {
// There is only getDecoratedClass() declared -> dispatch to proxy config.
return AopProxyUtils.ultimateTargetClass(this.advised);
}
else 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;
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// Get as late as possible to minimize the time we "own" the target,
// in case it comes from a pool. 获取到目标对象的地方
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
// Get the interception chain for this method. 获取定义好的拦截器
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
// Check whether we have any advice. If we don't, we can fall back 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. 如果没有设定拦截器,直接调用target的对应方法
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// We need to create a method invocation...
// 如果有拦截器,需要调用拦截器之后才调用目标对象的方法
MethodInvocation invocation =
new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// Proceed to the joinpoint through the interceptor chain. 沿着拦截器链继续前进
retVal = invocation.proceed();
}
// Massage return value if necessary.
Class<?> returnType = method.getReturnType();
if (retVal != null && retVal == target &&
returnType != Object.class && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
// Special case: it returned "this" and the return type of the method
// is type-compatible. Note that we can't help if the target sets
// a reference to itself in another returned object.
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);
}
}
}
CglibAopProxy的intercept拦截
在分析CglibAopProxy的AopProxy代理对象生成的时候,我们了解到对于AOP的拦截调用,其回调是在DynamicAdvisedInterceptor对象中实现的,这个回调的实现在intercept方法中,如下代码清单所示。CglibAopProxy的intercept回调方法的实现和JdkDynamicAopProxy的回调实现是非常类似的,只是在CglibAopProxy中构造CglibMethodInvocation对象来完成拦截器链的调用,而在JdkDynamicAopProxy中是通过构造ReflectiveMethodInvocation对象来完成这个功能的。
org.springframework.aop.framework.CglibAopProxy.DynamicAdvisedInterceptor#intercept的实现如下:
ini
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
Object target = null;
TargetSource targetSource = this.advised.getTargetSource();
try {
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// Get as late as possible to minimize the time we "own" the target, in case it comes from a pool...
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
// 从this.advised中取得配置好的AOP通知
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
Object retVal;
// 如果没有AOP通知配置,直接调用target对象的调用方法
if (chain.isEmpty() && CglibMethodInvocation.isMethodProxyCompatible(method)) {
// 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.
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = invokeMethod(target, method, argsToUse, methodProxy);
}
else {
// We need to create a method invocation... 通过CglibMethodInvocation来启动advice通知
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
}
retVal = processReturnType(proxy, target, method, retVal);
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
目标对象方法的调用
如果没有设置拦截器,那么会对目标对象的方法直接进行调用。对于JdkDynamicAopProxy代理对象,这个对目标对象的方法调用是通过AopUtils使用反射机制在AopUtils.invokeJoinpointUsingReflection的方法中实现的,如下代码清单所示。在这个调用中,首先得到调用方法的反射对象,然后使用invoke启动对方法反射对象的调用。
org.springframework.aop.support.AopUtils#invokeJoinpointUsingReflection的实现如下:
typescript
public static Object invokeJoinpointUsingReflection(@Nullable Object target, Method method, Object[] args)
throws Throwable {
// Use reflection to invoke the method. 使用反射机制调用代理方法
try {
ReflectionUtils.makeAccessible(method);
return method.invoke(target, args);
}
catch (InvocationTargetException ex) {
// Invoked method threw a checked exception.
// We must rethrow it. The client won't see the interceptor.
throw ex.getTargetException();
}
catch (IllegalArgumentException ex) {
throw new AopInvocationException("AOP configuration seems to be invalid: tried calling method [" +
method + "] on target [" + target + "]", ex);
}
catch (IllegalAccessException ex) {
throw new AopInvocationException("Could not access method [" + method + "]", ex);
}
}
对于使用CglibAopProxy的代理对象,它对自标对象的调用是通过CGLIB的MethodProxy对象来直接完成的,这个对象的使用是由CGLIB的设计决定的。具体的调用在DynamicAdvisedInterceptor的intercept方法中可以看到,使用的是CGLIB封装好的功能,相对JdkDynamicAopProxy的实现来说,形式上看起来较为简单,但它们的功能却是一样的,都是完成对目标对象方法的调用,具体的代码实现如下。
java.lang.reflect.Method#invoke的实现如下:
ini
public Object invoke(Object obj, Object... args)
throws IllegalAccessException, IllegalArgumentException,
InvocationTargetException
{
if (!override) {
if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, clazz, obj, modifiers);
}
}
MethodAccessor ma = methodAccessor; // read volatile
if (ma == null) {
ma = acquireMethodAccessor();
}
return ma.invoke(obj, args);
}
AOP拦截器链的调用
在了解了对目标对象的直接调用以后,开始进入AOP实现的核心部分了,AOP是怎样完成对目标对象的增强的?这些实现封装在AOP拦截器链中,由一个个具体的拦截器来完成。前面介绍了使用JDK和CGLIB会生成不同的AopProxy代理对象,从而构造了不同的回调方法来启动对拦截器链的调用,比如在JdkDynamicAopProxy中的invoke方法,以及在CglibAopProxy中使用DynamicAdvisedInterceptor的intercept方法。虽然它们使用了不同的 AopProxy代理对象,但最终对AOP拦截的处理可谓殊途同归:它们对拦截器链的调用都是在ReflectiveMethodInvocation中通过proceed方法实现的。在proceed方法中,会逐个运行拦截器的拦截方法。在运行拦截器的拦截方法之前,需要对代理方法完成一个匹配判断,通过这个匹配判断来决定拦截器是否满足切面增强的要求。大家一定还记得前面提到的,在Pointcut切点中需要进行matches的匹配过程,即matches调用对方法进行匹配判断,来决定是否需要实行通知增强。以下看到的调用就是进行matches的地方,具体的处理过程在ReflectiveMethodInvocation的proceed方法中,如下代码清单所示。在proceed方法中,先进行判断,如果现在已经运行到拦截器链的末尾,那么就会直接调用目标对象的实现方法,否则,沿着拦截器链继续进行,得到下一个拦截器,通过这个拦截器进行matches判断,判断是否是适用于横切增强的场合,如果是,从拦截器中得到通知器,并启动通知器的invoke方法进行切面增强。在这个过程结束以后,会迭代调用proceed方法,直到拦截器链中的拦截器都完成以上的拦截过程为止。
org.springframework.aop.framework.ReflectiveMethodInvocation#proceed的实现如下:
kotlin
public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
// 从索引为-1的拦截器开始调用,依次顺序调用,如果拦截器链中的拦截器迭代调用完毕,这里开始调用target的函数,反射机制完成,实现为下面的invokeJoinpoint的实现
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.
// 对拦截器进行动态匹配的判断,前面分析的PointCut,这里是触发机进行匹配的地方,如果和定义的PointCut匹配,那么这个advice将会得到执行
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
// Dynamic matching failed.
// Skip this interceptor and invoke the next in the chain.
// 如果不匹配,proceed会被递归调用,直到所有的拦截器都被运行过为止
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);
}
}
kotlin
protected Object invokeJoinpoint() throws Throwable {
return AopUtils.invokeJoinpointUsingReflection(this.target, this.method, this.arguments);
}
org.springframework.aop.support.AopUtils#invokeJoinpointUsingReflection的实现如下:
typescript
public static Object invokeJoinpointUsingReflection(@Nullable Object target, Method method, Object[] args)
throws Throwable {
// Use reflection to invoke the method. 使用反射机制调用target对象的方法
try {
ReflectionUtils.makeAccessible(method);
return method.invoke(target, args);
}
catch (InvocationTargetException ex) {
// Invoked method threw a checked exception.
// We must rethrow it. The client won't see the interceptor.
throw ex.getTargetException();
}
catch (IllegalArgumentException ex) {
throw new AopInvocationException("AOP configuration seems to be invalid: tried calling method [" +
method + "] on target [" + target + "]", ex);
}
catch (IllegalAccessException ex) {
throw new AopInvocationException("Could not access method [" + method + "]", ex);
}
}
以上就是整个拦截器及target自标对象方法被调用的过程。"小荷才露尖尖角",我们已经在这里看到对advice通知的调用入口了,虽然这个大名鼎鼎的advice到现在还没有完全现身,但已经看到了它的运行轨迹。先提出几个问题来提提大家的兴趣:这些advisor是怎样从配置文件中获得,并配置到proxy的拦截器链中去的?我们平常使用的advice通知是怎样起作用的?这些都是了解AOP实现原理的重要问题,下面就这些问题已经展示的线索继续展开分 析,去寻求这些问题的容案。
配置通知器
在整个AopProxy代理对象的拦截回调过程中,先回到ReflectiveMethodInvocation类的proceed方法。在这个方法里,可以看到得到了配置的interceptorOrInterceptionAdvice,如下所示:
kotlin
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
这个interceptorOrInterceptionAdvice是获得的拦截器,它通过拦截器机制对目标对象的行为增强起作用。这个拦截器来自interceptorsAndDynamicMethodMatchers,具体来说,它是interceptorsAndDynamicMethodMatchers持有的List中的一个元素。关于如何配置拦截器的同题,就转化为这个List中的拦截器元素是从哪单来,在哪里配置的问题。接着对invoke调用进行回放,回到JdkDynamicAopProxy中的invoke方法中,可以看到这个List中的interceptors是在哪个调用中获取的。对于CglibAopProxy,也有类似的过程,只不过这个过程是在DynamicAdvisedInterceptor的intercept回调中实现的,如下所示:
ini
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, rootClass);
在上面的代码中可以看到,获取interceptors的操作是由advised对象完成的,这个advised是一个AdvisedSupport对象,从类的继承关系上看,这个AdvisedSupport类同时也是ProxyFactoryBean的基类。从AdvisedSupport的代码中可以看到getInterceptorsAndDynamicInterceptionAdvice的实现,如下代码清单所示。在这个方法中取得了拦截器链,在取得拦截器链的时候,为提高取得拦截器链的效率,还为这个拦截器链设置了缓存。
kotlin
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
// 这里使用了cache,利用cache去获取已有的inteceptor链,但是第一次还是要自己动手生成的,这个inteceptor链的生成是由advisorchainFactory完成的,在这里使用的是DefaultAdvisorchainFactory
MethodCacheKey cacheKey = new MethodCacheKey(method);
List<Object> cached = this.methodCache.get(cacheKey);
if (cached == null) {
cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
this, method, targetClass);
this.methodCache.put(cacheKey, cached);
}
return cached;
}
取得拦截器链的工作是由配置好的advisorChainFactory来完成的,从名字上可以猜到,它是一个生成通知器链的工厂。在这里,advisorChainFactory被配置成一个DefaultAdvisorChainFactory对象,在DefaultAdvisorChainFactory中实现了interceptor链的获取过程,如下代码清单所示。在这个获取过程中,首先设置了一个List,其长度是由配置的通知器的个数来决定的,这个配置就是在XML中对ProxyFactoryBean做的interceptNames属性的配置。然后,DefaultAdvisorChainFactory会通过一个AdvisorAdapterRegistry来实现拦 截器的注册,AdvisorAdapterRegistry对advice通知的织入功能起了很大的作用,关于AdvisorAdapterRegistry对象的实现原理,会在后面分析通知是如何实现增强的部分进行阐述。有了AdvisorAdapterRegistry注册器,利用它来对从ProxyFactoryBean配置中得到的通知进行适配,从而获得相应的拦截器,再把它加入前面设置好的ist中去,完成所调的拦截器注册过程。在拦截器适配和注册过程完成以后,List中的拦截器会被JDK生成的AopProxy代理对象的invoke方法或者CGLIB代理对象的intercept拦截方法取得,并启动拦截器的invoke调用最络终钟发通知的切面增强。
org.springframework.aop.framework.DefaultAdvisorChainFactory的实现如下:
java
public class DefaultAdvisorChainFactory implements AdvisorChainFactory, Serializable {
@Override
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
Advised config, Method method, @Nullable Class<?> targetClass) {
// This is somewhat tricky... We have to process introductions first,
// but we need to preserve order in the ultimate list.
AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
// advisor链已经在config中持有了,直接使用
Advisor[] advisors = config.getAdvisors();
List<Object> interceptorList = new ArrayList<>(advisors.length);
Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
Boolean hasIntroductions = null;
for (Advisor advisor : advisors) {
if (advisor instanceof PointcutAdvisor) {
// Add it conditionally.
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
// 拦截器链是通过AdvisorAdapterRegistry来加入的,这个AdvisorAdapterRegistery对advice织入起了很大的作用,在后面的分析中会看到
MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
boolean match;
if (mm instanceof IntroductionAwareMethodMatcher) {
if (hasIntroductions == null) {
hasIntroductions = hasMatchingIntroductions(advisors, actualClass);
}
match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions);
}
else {
match = mm.matches(method, actualClass);
}
if (match) {
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
if (mm.isRuntime()) {
// Creating a new object instance in the getInterceptors() method
// isn't a problem as we normally cache created chains.
for (MethodInterceptor interceptor : interceptors) {
interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
}
}
else {
interceptorList.addAll(Arrays.asList(interceptors));
}
}
}
}
else if (advisor instanceof IntroductionAdvisor) {
IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
else {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
return interceptorList;
}
/**
* Determine whether the Advisors contain matching introductions.
*/
private static boolean hasMatchingIntroductions(Advisor[] advisors, Class<?> actualClass) {
for (Advisor advisor : advisors) {
if (advisor instanceof IntroductionAdvisor) {
IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
if (ia.getClassFilter().matches(actualClass)) {
return true;
}
}
}
return false;
}
}
事实上,这里的advisor通知器是从AdvisorSupport取得的,从对它的调用过程来看会比较清楚。
如下是对AdvisedSupport.addAdvisors的调用关系图:

在ProxyFactoryBean的getObject方法中对advisor进行初始化时,从XML配置中获取了advisor通知器。在ProxyFactoryBean中,对advisor进行初始化的代码实现如下代码清单所示。在这个初始化的advisor中,可以看到对IoC容器的个getBean回调,通过对这个IoC容器的getBean调用来得到配置好的advisor通知器。
org.springframework.aop.framework.ProxyFactoryBean#initializeAdvisorChain的实现如下:
kotlin
private synchronized void initializeAdvisorChain() throws AopConfigException, BeansException {
if (!this.advisorChainInitialized && !ObjectUtils.isEmpty(this.interceptorNames)) {
if (this.beanFactory == null) {
throw new IllegalStateException("No BeanFactory available anymore (probably due to serialization) " +
"- cannot resolve interceptor names " + Arrays.toString(this.interceptorNames));
}
// Globals can't be last unless we specified a targetSource using the property...
if (this.interceptorNames[this.interceptorNames.length - 1].endsWith(GLOBAL_SUFFIX) &&
this.targetName == null && this.targetSource == EMPTY_TARGET_SOURCE) {
throw new AopConfigException("Target required after globals");
}
// Materialize interceptor chain from bean names.
for (String name : this.interceptorNames) {
if (name.endsWith(GLOBAL_SUFFIX)) {
if (!(this.beanFactory instanceof ListableBeanFactory)) {
throw new AopConfigException(
"Can only use global advisors or interceptors with a ListableBeanFactory");
}
addGlobalAdvisors((ListableBeanFactory) this.beanFactory,
name.substring(0, name.length() - GLOBAL_SUFFIX.length()));
}
else {
// If we get here, we need to add a named interceptor.
// We must check if it's a singleton or prototype.
// 判断类类型,单件类型和prototype类型的处理是不一样的
Object advice;
if (this.singleton || this.beanFactory.isSingleton(name)) {
// Add the real Advisor/Advice to the chain.
// 通过beanFactory取得advisor,
advice = this.beanFactory.getBean(name);
}
else {
// It's a prototype Advice or Advisor: replace with a prototype.
// Avoid unnecessary creation of prototype bean just for advisor chain initialization.
advice = new PrototypePlaceholderAdvisor(name);
}
addAdvisorOnChainCreation(advice);
}
}
this.advisorChainInitialized = true;
}
}
advisor通知器的取得是委托给IoC容器完成的,但是在ProxyFactoryBean中是如何获得IoC容器,然后通过回调IoC容器的getBean方法来得到需要的通知器advisor的呢?这涉及IoC容器实现原理,在使用DefaultListableBeanFactory作为IoC容器的时候,它的基类是AbstractAutowireCapableBeanFactory,在这个基类中可以看到一个对Bean进行初始化的initializeBean方法。在这个Bean的初始化过程中,对IoC容器在Bean中的回调进行了设置。这个设置很简单,首先,判断这个Bean的类型是不是实现了BeanFactoryAware接口,如果是,那么它一定实现了BeanFactoryAware定义的接口方法,通过这个接口方法,可以把IoC容器设置到Bean自身定义的一个属性中去。这样,在这个Bean的自身实现中,就能够得到它所在的IoC容器,从而调用IoC容器的getBean方法,完成对IoC容器的回调,就像一个有特异功能的Bean一样,除了使用为自已设计的功能之外,还可以去调用它所在的容器的功能,如下所示:
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#invokeAwareMethods中的实现如下:
scss
if (bean instanceof BeanNameAware) {
((BeanNameAware) bean).setBeanName(beanName);
}
对于IoC容器的使用,如果需要回调容器,前提是当前的Bean需要实现BeanFactoryAware接口,这个接口只需要实现一个接口方法setBeanFactory,同时设置一个属性来持有BeanFactory的IoC容器,就可以在Bean中取得IoC容器进行回调了。在IoC容器对Bean进行初始化的时候,会对Bean的类型进行判断,如果这是一个BeanFactoryAware的Bean类型,那么IoC容器会调用这个Bean的setBeanFactory方法,完成对这个BeanFactory在Bean中的设置。具体来说,ProxyFactoryBean实现了这个接口,所以在它的初始化完成以后,可以在Bean中 使用容器进行回调。这里设置的this对象,就是Bean所在的IoC容器,一般是DefaultListableBeanFactory对象。在得到这个设置好的BeanFactory以后,ProxyFactoryBean就可以通过回调容器的getBean去获取配置在Bean定义文件中的通知器了,获取通知器就是向IoC容器回调getBean的过程。了解IoC容器实现原理的读者都知道,这个getBean是IoC容器一个非常基本的方法。在调用时,ProxyFactoryBean需要给出通知器的名字,而这些名字都是在interceptorNames的List中已经配置好的,在IoC对FactoryBean进行依赖注入时,会直接注人到FactoryBean的interceptorNames的属性中。完成这个过程以后,ProxyFactoryBean就获得了配置的通知器,为完成切面增强做好准备。
Advice通知的实现
经过前面的分析,我们看到在AopProxy代理对象生成时,其拦截器也同样建立起来了,除此之外,我们还了解了拦截器的挡截调用和最终目标对象的方法调用的实现原理。但是,对于AOP实现的重要部分,SpringAOP定义的通知是怎样实现对目标对象的增强的呢?本小节将探讨这个问题。读者一定还记得,在为AopProxy代理对象配置拦截器的实现中,有一个取得挡截器的配置过程,这个过程是由DefaultAdvisorChainFactory实现的,而这个工厂类负责生成拦截器链,在它的getInterceptorsAndDynamicInterceptionAdvice方法中,有一个适配和注册过程,在这个适配和注册过程中,通过配置Spring预先设计好的拦截器,Spring加入了它对AOP实现的处理。为详细了解这个过程,先从DefaultAdvisorChainFactory的实现开始如下代码清单所示。可以看到,在DefaultAdvisorChainFactory的实现中,首先构造了一-个GlobalAdvisorAdapterRegistry单件,然后,对配置的Advisor通知器进行逐个遍历,这些通知器链都是配置在interceptorNames中的,从getInterceptorsAndDynamiclnterceptionAdvice传递进来的advised参数对象中,可以方便地取得配置的通知器,有了这些通知器,接着就是一个由GlobalAdvisorAdapterRegistry来完成的拦截器的适配和注册过程。
org.springframework.aop.framework.DefaultAdvisorChainFactory的实现如下:
scss
public class DefaultAdvisorChainFactory implements AdvisorChainFactory, Serializable {
@Override
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
Advised config, Method method, @Nullable Class<?> targetClass) {
// This is somewhat tricky... We have to process introductions first,
// but we need to preserve order in the ultimate list.
// 得到注册器GlobalAdvisorAdapterRegistery,这是一个单件模式的实现
AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
Advisor[] advisors = config.getAdvisors();
List<Object> interceptorList = new ArrayList<>(advisors.length);
Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
Boolean hasIntroductions = null;
for (Advisor advisor : advisors) {
if (advisor instanceof PointcutAdvisor) {
// Add it conditionally.
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
boolean match;
if (mm instanceof IntroductionAwareMethodMatcher) {
if (hasIntroductions == null) {
hasIntroductions = hasMatchingIntroductions(advisors, actualClass);
}
match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions);
}
else {
match = mm.matches(method, actualClass);
}
if (match) {
// getInterceptors方法中创建新的拦截器对象实例
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
if (mm.isRuntime()) {
// Creating a new object instance in the getInterceptors() method
// isn't a problem as we normally cache created chains.
for (MethodInterceptor interceptor : interceptors) {
interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
}
}
else {
interceptorList.addAll(Arrays.asList(interceptors));
}
}
}
}
else if (advisor instanceof IntroductionAdvisor) {
IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
else {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
return interceptorList;
}
/**
* Determine whether the Advisors contain matching introductions.
*/
private static boolean hasMatchingIntroductions(Advisor[] advisors, Class<?> actualClass) {
for (Advisor advisor : advisors) {
if (advisor instanceof IntroductionAdvisor) {
IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
if (ia.getClassFilter().matches(actualClass)) {
return true;
}
}
}
return false;
}
}
仔细瑞摩了以上代码的读者一定会注意到,在这个GlobalAdvisorAdapterRegistry中隐藏不少AOP实现的重要细节,它的getInterceptors方法为AOP实现做出了很大的贡献,就是这个方法封装着advice织入实现的入口,我们先从GlobalAdvisorAdapterRegistry的实现人手如下代码清单所示。从代码上看,GlobalAdvisorAdapterRegistry的实现很简洁,起到的基本上是一个适配器的作用,但同时它也是一个单件模式的应用,为SpringAOP模块提供了一个DefaultAdvisorAdapterRegistry单件,这个DefaultAdvisorAdapterRegistry是下面要分析的重点,像它的名字一样,由它来完成各种通知的适配和注册工作。
org.springframework.aop.framework.adapter.GlobalAdvisorAdapterRegistry实现如下:
csharp
public final class GlobalAdvisorAdapterRegistry {
private GlobalAdvisorAdapterRegistry() {
}
/**
* Keep track of a single instance so we can return it to classes that request it.
*/
private static AdvisorAdapterRegistry instance = new DefaultAdvisorAdapterRegistry();
/**
* Return the singleton {@link DefaultAdvisorAdapterRegistry} instance.
*/
public static AdvisorAdapterRegistry getInstance() {
return instance;
}
/**
* Reset the singleton {@link DefaultAdvisorAdapterRegistry}, removing any
* {@link AdvisorAdapterRegistry#registerAdvisorAdapter(AdvisorAdapter) registered}
* adapters.
*/
static void reset() {
instance = new DefaultAdvisorAdapterRegistry();
}
}
在DefaultAdvisorAdapterRegistry中,设置了一系列的adapter适配器,正是这些adapter适配器的实现,为SpringAOP的advice提供编织能力。下面看一下DefaultAdvisorAdapterRegistry中究竟发生了什么,如下代码清单所示。首先,我们看到了一系列在AOP应用中与用到的SpringAOP的advice通知相对应的adapter适配实现,并看到了对这些adapter的具体使用。具体说来,对它们的使用主要体现在以下两个方面:一是调用adapter的support方法,通过这个方法来判断取得的advice属于什么类型的advice通知,从而根据不同的advice类型来注册不同的Advicelnterceptor,也就是前面看到的那些拦截器:另一方面,这些AdviceInterceptor都是SpringAOP框架设计好了的,是为实现不同的advice功能提供服务的。有了这些Advicelnterceptor,可以方便地使用由Spring提供的各种不同的advice来设计AOP应用。也就是说,正是这些AdviceInterceptor最终实现了advice通知在AopProxy代理对象中的织入功能。
org.springframework.aop.framework.adapter.DefaultAdvisorAdapterRegistry的实现如下:
java
public class DefaultAdvisorAdapterRegistry implements AdvisorAdapterRegistry, Serializable {
// 持有一个AdvisorAdapter的List,这个List中的Adapter是与实现Spring AOP的advice增强功能对应的
private final List<AdvisorAdapter> adapters = new ArrayList<>(3);
// 在初始化中将AOP的advice的封装实现放入adapters中
public DefaultAdvisorAdapterRegistry() {
registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
registerAdvisorAdapter(new AfterReturningAdviceAdapter());
registerAdvisorAdapter(new ThrowsAdviceAdapter());
}
@Override
public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {
if (adviceObject instanceof Advisor) {
return (Advisor) adviceObject;
}
if (!(adviceObject instanceof Advice)) {
throw new UnknownAdviceTypeException(adviceObject);
}
Advice advice = (Advice) adviceObject;
if (advice instanceof MethodInterceptor) {
// So well-known it doesn't even need an adapter.
return new DefaultPointcutAdvisor(advice);
}
for (AdvisorAdapter adapter : this.adapters) {
// Check that it is supported.
if (adapter.supportsAdvice(advice)) {
return new DefaultPointcutAdvisor(advice);
}
}
throw new UnknownAdviceTypeException(advice);
}
@Override
public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
List<MethodInterceptor> interceptors = new ArrayList<>(3);
// 从Advisor通知器配置中取得advice通知
Advice advice = advisor.getAdvice();
// 如果通知是MethodInterceptor类型的通知,直接加入interceptors的List中,不需要适配
if (advice instanceof MethodInterceptor) {
interceptors.add((MethodInterceptor) advice);
}
// 对通知进行适配,使用已经配置好的Adapter,然后从对应的adapter中取出封装好AOP编织功能的拦截器
for (AdvisorAdapter adapter : this.adapters) {
if (adapter.supportsAdvice(advice)) {
interceptors.add(adapter.getInterceptor(advisor));
}
}
if (interceptors.isEmpty()) {
throw new UnknownAdviceTypeException(advisor.getAdvice());
}
return interceptors.toArray(new MethodInterceptor[0]);
}
@Override
public void registerAdvisorAdapter(AdvisorAdapter adapter) {
this.adapters.add(adapter);
}
}
AdvisorAdapter的实现类如下,它们均直接继承AdvisorAdapter类:
scss
MethodBeforeAdviceAdapter (org.springframework.aop.framework.adapter)
ThrowsAdviceAdapter (org.springframework.aop.framework.adapter)
AfterReturningAdviceAdapter (org.springframework.aop.framework.adapter)
org.springframework.aop.framework.adapter.MethodBeforeAdviceAdapter的实现如下:
typescript
class MethodBeforeAdviceAdapter implements AdvisorAdapter, Serializable {
@Override
public boolean supportsAdvice(Advice advice) {
return (advice instanceof MethodBeforeAdvice);
}
@Override
public MethodInterceptor getInterceptor(Advisor advisor) {
MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice();
return new MethodBeforeAdviceInterceptor(advice);
}
}
org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor的实现如下:
kotlin
public class MethodBeforeAdviceInterceptor implements MethodInterceptor, BeforeAdvice, Serializable {
private final MethodBeforeAdvice advice;
/**
* Create a new MethodBeforeAdviceInterceptor for the given advice.
* @param advice the MethodBeforeAdvice to wrap
*/
public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {
Assert.notNull(advice, "Advice must not be null");
this.advice = advice;
}
@Override
@Nullable
public Object invoke(MethodInvocation mi) throws Throwable {
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
return mi.proceed();
}
}
Spring AOP为了实现advice的织入,设计了特定的拦截器对这些功能进行了封装。MethodBeforeAdviceInterceptor为例,实现的是对MethodBeforeAdvice的封装,在MethodBeforeAdviceInterceptor的invoke方法回调中看到,首先触发了advice的before回调,然后才是MethodInvocation的proceed方法调用。看到这里,就已经与前面在ReflectiveMethodInvocation的proceed分析中联系起来了。回忆一下,在AopProxy代理对象触发的ReflectiveMethodInvocation的proceed方法中,在取得拦截器以后,启动了对截器invoke方法的调用。按照AOP的配置规则,ReflectiveMethodInvocation触发的拦截器invoke方法,最终会根据不同的advice类型,触发Spring对不同的advice的拦截器封装,比如对MethodBeforeAdvice,最终会触发MethodBeforeAdviceInterceptor的invoke方法。在MethodBeforeAdviceInterceptor方法中,会先调用advice的before方法,这就是MethodBeforeAdvice所需要的对目标对象的增强效果:在方法调用之前完成通知增强。
其他的MethodInterceptor的实现类似。
org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor的实现如下:
kotlin
public class AfterReturningAdviceInterceptor implements MethodInterceptor, AfterAdvice, Serializable {
private final AfterReturningAdvice advice;
/**
* Create a new AfterReturningAdviceInterceptor for the given advice.
* @param advice the AfterReturningAdvice to wrap
*/
public AfterReturningAdviceInterceptor(AfterReturningAdvice advice) {
Assert.notNull(advice, "Advice must not be null");
this.advice = advice;
}
// 先执行target的proceed方法,再对返回结果进行处理
@Override
@Nullable
public Object invoke(MethodInvocation mi) throws Throwable {
Object retVal = mi.proceed();
this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
return retVal;
}
}
org.springframework.aop.framework.adapter.ThrowsAdviceInterceptor的实现如下:
java
public class ThrowsAdviceInterceptor implements MethodInterceptor, AfterAdvice {
private static final String AFTER_THROWING = "afterThrowing";
private static final Log logger = LogFactory.getLog(ThrowsAdviceInterceptor.class);
private final Object throwsAdvice;
/** Methods on throws advice, keyed by exception class. */
private final Map<Class<?>, Method> exceptionHandlerMap = new HashMap<>();
/**
* Create a new ThrowsAdviceInterceptor for the given ThrowsAdvice.
* @param throwsAdvice the advice object that defines the exception handler methods
* (usually a {@link org.springframework.aop.ThrowsAdvice} implementation)
*/
public ThrowsAdviceInterceptor(Object throwsAdvice) {
Assert.notNull(throwsAdvice, "Advice must not be null");
this.throwsAdvice = throwsAdvice;
Method[] methods = throwsAdvice.getClass().getMethods();
for (Method method : methods) {
if (method.getName().equals(AFTER_THROWING) &&
(method.getParameterCount() == 1 || method.getParameterCount() == 4)) {
Class<?> throwableParam = method.getParameterTypes()[method.getParameterCount() - 1];
if (Throwable.class.isAssignableFrom(throwableParam)) {
// An exception handler to register...
// 配置异常处理
this.exceptionHandlerMap.put(throwableParam, method);
if (logger.isDebugEnabled()) {
logger.debug("Found exception handler method on throws advice: " + method);
}
}
}
}
if (this.exceptionHandlerMap.isEmpty()) {
throw new IllegalArgumentException(
"At least one handler method must be found in class [" + throwsAdvice.getClass() + "]");
}
}
/**
* Return the number of handler methods in this advice.
*/
public int getHandlerMethodCount() {
return this.exceptionHandlerMap.size();
}
@Override
@Nullable
public Object invoke(MethodInvocation mi) throws Throwable {
// 把对目标对象的方法调用放入try/catch中,并在catch中触发ThrowsAdvice的回调
try {
return mi.proceed();
}
catch (Throwable ex) {
Method handlerMethod = getExceptionHandler(ex);
if (handlerMethod != null) {
invokeHandlerMethod(mi, ex, handlerMethod);
}
throw ex;
}
}
/**
* Determine the exception handle method for the given exception.
* @param exception the exception thrown
* @return a handler for the given exception type, or {@code null} if none found
*/
@Nullable
private Method getExceptionHandler(Throwable exception) {
Class<?> exceptionClass = exception.getClass();
if (logger.isTraceEnabled()) {
logger.trace("Trying to find handler for exception of type [" + exceptionClass.getName() + "]");
}
Method handler = this.exceptionHandlerMap.get(exceptionClass);
while (handler == null && exceptionClass != Throwable.class) {
exceptionClass = exceptionClass.getSuperclass();
handler = this.exceptionHandlerMap.get(exceptionClass);
}
if (handler != null && logger.isTraceEnabled()) {
logger.trace("Found handler for exception of type [" + exceptionClass.getName() + "]: " + handler);
}
return handler;
}
private void invokeHandlerMethod(MethodInvocation mi, Throwable ex, Method method) throws Throwable {
Object[] handlerArgs;
if (method.getParameterCount() == 1) {
handlerArgs = new Object[] {ex};
}
else {
handlerArgs = new Object[] {mi.getMethod(), mi.getArguments(), mi.getThis(), ex};
}
try {
method.invoke(this.throwsAdvice, handlerArgs);
}
catch (InvocationTargetException targetEx) {
throw targetEx.getTargetException();
}
}
}
ProxyFactory实现AOP
在前面的分析中,我们了解了以ProxyFactoryBean为例SpringAOP的实现线索。回到前面提到的SpringAOP的类层次关系,从中看到,除了使用ProxyFactoryBean实现AOP应用之外,还可以使用ProxyFactory来实现SpringAOP的功能,只是在使用ProxyFactory的时候,需要编程式地完成AOP应用的设置。下面举-个使用ProxyFactory的例子,如下代码清单所示。
ini
TestBean target = new TestBean();
ProxyFactory pf = new ProxyFactory(target);
NopInterceptor nop = new NopInterceptor();
CountingBeforeAdvice cba = new CountingBeforeAdvice();
Advisor advisor = new DefaultPointcutAdvisor(cba);
pf.addAdvice(nop);
pf.addAdvisor(advisor);
ITestBean proxied = (ITestBean) pf.getProxy();
对于使用ProxyFactory实现AOP功能,其实现原理与ProxyFactoryBean的实现原理是一样的,只是在最外层的表现形式上有所不同。ProxyFactory没有使用FactoryBean的IoC封装,而是通过直接继承ProxyCreatorSupport的功能来完成AOP的属性配置。至于其他ProxyCreatorSupport的子类,ProxyFactory取得AopProxy代理对象其实是和ProxyFactoryBean一样的,一般来说,也是以getProxy为人口,由DefaultAopProxyFactory来完成的。关于取得AopProxy的详细分析和以后对拦截器调用的实现原理,前面都分析过了这里不再重复。对ProxyFactory实现感兴趣的读者,可以从如下代码清单中看到它与ProxyFactoryBean实现上不同的地方。从代码清单中可以看到,由ProxyFactory的getProxy方法取得AopProxy代理对象,getProxy方法的实现使用了ProxyFactory的基类ProxyCreatorSupport的createProxy方法来生成AopProxy代理对象,而AopProxy代理对象的生成是由AopProxyFactory来完成的,它会生成JDK或者CGLIB的代理对象。从这里的getProxy的实现开始,ProxyFactory和ProxyFactoryBean在AOP的功能实现上,包括以后拦截器的调用等基本上都是一样的。
org.springframework.aop.framework.ProxyFactory的生成代理对象的方法实现如下:
typescript
public static Object getProxy(TargetSource targetSource) {
if (targetSource.getTargetClass() == null) {
throw new IllegalArgumentException("Cannot create class proxy for TargetSource with null target class");
}
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTargetSource(targetSource);
proxyFactory.setProxyTargetClass(true);
return proxyFactory.getProxy();
}
Spring AOP的高级特性
了解了SpringAOP的基本实现,下面通过一个使用SpringAOP高级特性的例子,来了解它的实现原理。在使用SpringAOP时,对目标对象的增强是通过挡截器来完成的。对于一些应用场合,需要对目标对象本身进行一些处理,比如,如何从一个对象池或对象工厂中获得目标对象等。对于这种情况,需要使用Spring的TargetSource接口特性,在这里,把这类AOP特性当成高级特性的一种,通过对这些AOP特性的实现原理的了解,可以实现对AOP基本特性的灵活运用。 Spring提供了许多现成的TargetSource实现,比如HotSwappableTargetSource,HotSwappableTargetSource使用户可以以线程安全的方式切换目标对象,提供所谓的热交换功能,即实现当调用者保持引用的时候,切换一个动态代理的目标。这个特性是很有用的,尽管它的开启需要AOP应用进行显式的配置,但配置并不复杂,在便用时,只需要把HotSwappableTargetSource配置到ProxyFactoryBean的target属性就可以了,在需要更换真正的自标对象时,调用HotSwappableTargetSource的swap方法就可以完成。由此可见,对HotSwappableTargetSource的热交换功能的使用,是需要触发swap方法调用的。这个swap方法的实现很简单,它完成target对象的替换,也就是说,它使用新的target对象来替换原有的target对象。为了保证线程安全,需要把这个替换方法设为synchronized方法,如下代码清单所示。
org.springframework.aop.target.HotSwappableTargetSource#swap实现如下:
java
public synchronized Object swap(Object newTarget) throws IllegalArgumentException {
Assert.notNull(newTarget, "Target object must not be null");
Object old = this.target;
this.target = newTarget;
return old;
}
使用较少,后续作为专题进行探讨。