前言
前面两篇关于 Spring AOP 的文章基本把 Spring AOP 的内容都讲的差不多了,包括动态代理,拦截器,切点,切面和通知等。相信读了前面文章的同学也已经知道了怎么解析切面,怎么根据切面去匹配需要增强的被代理对象,也知道了怎么生成动态代理。
我们知道了怎么做,可是还不知道什么时候做,上述的各个节点都是什么时候触发的呢?我们知道bean的生命周期主要包括实例化 bean, 属性注入,初始化方法的调用。对一个对象增强首先要有一个对象,那么增强一定是在这个 bean 被实例化之后,Spring AOP 只涉及方法的增强。所以属性注入应该也是要在增强之前的,不然生成代理对象之后还得给代理对象进行属性赋值,多麻烦呀,同理,初始化方法也不会被增强,那么生成代理对象应该也要在目标 bean 调用完初始化方法之后进行的。不然生成代理对象之后还得专门调用一下初始化方法,可以说是很没必要了。所以我们推测对目标对象的增强应该是在 bean 调用完初始化方法之后进行的。
此外我们上一篇文章提到了一个bean后置处理器 AnnotationAwareAspectJAutoProxyCreator,就是通过它和它的父类的一些方法,才完成了解析切面和进行增强的功能。因为只有先实例化才可以调用其中的方法。那么它是什么时候实例化的呢?
AnnotationAwareAspectJAutoProxyCreator 什么时候实例化的?
我们在前面 @Import 注解使用及原理解析 讲解了如何通过 @Import 来注入一个实例 bean, 其中一种方式就是通过 @Import 来引入 ImportBeanDefinitionRegistrar 接口的类来注册一个bean定义。AnnotationAwareAspectJAutoProxyCreator 就是通过这种方式注册的。
使用 Spring AOP 一定离不开 @EnableAspectJAutoProxy 注解,那么我们就看一下这个注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
/**
* Indicate whether subclass-based (CGLIB) proxies are to be created as opposed
* to standard Java interface-based proxies. The default is {@code false}.
*/
boolean proxyTargetClass() default false;
/**
* Indicate that the proxy should be exposed by the AOP framework as a {@code ThreadLocal}
* for retrieval via the {@link org.springframework.aop.framework.AopContext} class.
* Off by default, i.e. no guarantees that {@code AopContext} access will work.
* @since 4.3.1
*/
boolean exposeProxy() default false;
}
我们看到 @Import(AspectJAutoProxyRegistrar.class), 然后再跟进一下 AspectJAutoProxyRegistrar
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
/**
* Register, escalate, and configure the AspectJ auto proxy creator based on the value
* of the @{@link EnableAspectJAutoProxy#proxyTargetClass()} attribute on the importing
* {@code @Configuration} class.
*/
//解析配置类的时候会调用这个方法,注册 bean 定义
@Override
public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
//这个方法就是注册 bean 定义的
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
AnnotationAttributes enableAspectJAutoProxy =
AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
if (enableAspectJAutoProxy != null) {
if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}
}
}
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
return registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry, null);
}
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
BeanDefinitionRegistry registry, @Nullable Object source) {
// 这里我们看到,它传入了 AnnotationAwareAspectJAutoProxyCreator ,这正是我们寻找的
return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}
private static BeanDefinition registerOrEscalateApcAsRequired(
Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
//判断是否已经注册过该bean定义
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
int requiredPriority = findPriorityForClass(cls);
if (currentPriority < requiredPriority) {
apcDefinition.setBeanClassName(cls.getName());
}
}
return null;
}
//实例化一个bean定义
RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
beanDefinition.setSource(source);
beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
return beanDefinition;
}
上面的代码已经很清晰了。跟我们前面讲 @Import 那篇文章注册bean定义的样例差不多,如果看这块代码不是很清晰,建议去看下那篇文章,上面也已经给出了链接。至此我们AnnotationAwareAspectJAutoProxyCreator 的 bean 定义就通过 @Import 的方式给注入进来了
有了bean定义,在注册bean后置处理器的方法的时候,就会把该bean定义的bean给实例化出来了。这里简化调用流程直接分析 registerBeanPostProcessors 方法,这个在之前讲ConfigurationClassPostProcessor 的时候讲了详细的代码跟踪流程,不清楚的可以去那里看一下
public static void registerBeanPostProcessors(
ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
// Register BeanPostProcessorChecker that logs an info message when
// a bean is created during BeanPostProcessor instantiation, i.e. when
// a bean is not eligible for getting processed by all BeanPostProcessors.
int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));
// Separate between BeanPostProcessors that implement PriorityOrdered,
// Ordered, and the rest.
List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
List<String> orderedPostProcessorNames = new ArrayList<>();
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
priorityOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
}
else {
nonOrderedPostProcessorNames.add(ppName);
}
}
// First, register the BeanPostProcessors that implement PriorityOrdered.
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);
// Next, register the BeanPostProcessors that implement Ordered.
//AnnotationAwareAspectJAutoProxyCreator 实现了Ordered 接口,故会在这里遍历
List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
for (String ppName : orderedPostProcessorNames) {
//这里调用了getBean方法,就会把bean实例给创建出来了
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
orderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
sortPostProcessors(orderedPostProcessors, beanFactory);
//注册后置处理器
registerBeanPostProcessors(beanFactory, orderedPostProcessors);
// Now, register all regular BeanPostProcessors.
List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
for (String ppName : nonOrderedPostProcessorNames) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
nonOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);
// Finally, re-register all internal BeanPostProcessors.
sortPostProcessors(internalPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, internalPostProcessors);
// Re-register post-processor for detecting inner beans as ApplicationListeners,
// moving it to the end of the processor chain (for picking up proxies etc).
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
}
因为 AnnotationAwareAspectJAutoProxyCreator 继承了 Ordered 接口,所以他会在上述代码注释处通过getBean的方式创建出来,创建出来之后一定需要一个地方保管着,这时候可以跟进一下 registerBeanPostProcessors(beanFactory, orderedPostProcessors);
private static void registerBeanPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanPostProcessor> postProcessors) {
//遍历后置处理器实例,调用保存方法
for (BeanPostProcessor postProcessor : postProcessors) {
beanFactory.addBeanPostProcessor(postProcessor);
}
}
public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
Assert.notNull(beanPostProcessor, "BeanPostProcessor must not be null");
// Remove from old position, if any
this.beanPostProcessors.remove(beanPostProcessor);
// Track whether it is instantiation/destruction aware
if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor) {
this.hasInstantiationAwareBeanPostProcessors = true;
}
if (beanPostProcessor instanceof DestructionAwareBeanPostProcessor) {
this.hasDestructionAwareBeanPostProcessors = true;
}
// Add to end of list
//可以看到,将bean实例放入一个list中保存
this.beanPostProcessors.add(beanPostProcessor);
}
至此为止,我们知道解析切面和生成代理对象的一个很重要的工具类(后置处理器)是什么时候注册,实例化和保存起来的了。
什么时候对被代理对象增强?
从前言的分析中,我们可以猜测生成代理对象在bean创建出来并调用了初始化方法之后再进行增强比较好。那么到底是不是这样呢?首先我们看一下bean的实例化方法
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareMethods(beanName, bean);
return null;
}, getAccessControlContext());
}
else {
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
//调用 bean 的后置处理器方法
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
可以看到确实是调用了bean的后置处理器方法,那么它到底干了什么呢?
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
//遍历后置处理器数组,这个getBeanPostProcessors不会就是获取刚刚我们保存后置处理器的那个list把?
for (BeanPostProcessor processor : getBeanPostProcessors()) {
//调用bean的后置处理器方法,因为刚刚实例化的解析切面的后置处理器也在这个list中,所以也会调用它的后置处理器方法
Object current = processor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
public List<BeanPostProcessor> getBeanPostProcessors() {
//可以看到,这个确实就是刚刚保存bean后置处理器实例的list
return this.beanPostProcessors;
}
这里我们分析出了,确实是在bean调用初始化方法之后,调用bean的后置处理器方法来进行增强。即会调用如下方法
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
这个方法我们在上文中已经分析的很清楚了,所以我们也就知道它后面是如何解析切面并生成代理对象的了。
Spring AOP 代理对象的方法的流程(各个通知的执行顺序)
我们一般用的都是 jdk 动态代理,所以我们再结合第一篇的样例,讲一下 jdk 代理对象的执行流程。先看一下其对应的 invoke 方法
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 判断,主要是判断不需要增强的方法,比如equals,hashcode方法等,直接返回结果,节约时间。
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// The target does not implement the equals(Object) method itself.
return equals(args[0]);
}
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// The target does not implement the hashCode() method itself.
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.
//获取拦截器链,对于 Spring AOP 来说是获取到跟当前代理类匹配的所有 Advisor
List<Object> 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.
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);
}
}
}
这里有两个重要的方法,一是获取拦截器链方法,二是执行拦截器方法。注意本文在这里只讲解 Spring AOP 自动代理对象的执行流程,所以自定义拦截器链,不再本文的讨论范围。首先先看一下获取拦截器链的方法
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
//首先尝试从缓存中获取
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;
}
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();
//获取生成代理对象时设置的 advisors 数组。
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) {
// 如果看了前面的文章,应该知道 Spring AOP 生成的advisor 都是InstantiationModelAwarePointcutAdvisorImpl 实例,它实现了 PointcutAdvisor 接口
if (advisor instanceof PointcutAdvisor) {
// Add it conditionally.
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
//第一个参数在生成代理对象的时候就设置为true了,因为如果都给他生成代理对象了,说明这个类一定是需要被增强的。省略了第二个classFilter的执行。
if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
//这里获取到的方法匹配器即为切点本身AspectJExpressionPointcut,前面文章已经分析过了
MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
boolean match;
//AspectJExpressionPointcut 实现了 IntroductionAwareMethodMatcher 接口
if (mm instanceof IntroductionAwareMethodMatcher) {
if (hasIntroductions == null) {
//这里判断是否有IntroductionAdvisor拦截的,我们当前流程不会走一步
hasIntroductions = hasMatchingIntroductions(advisors, actualClass);
}
match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions);
}
else {
match = mm.matches(method, actualClass);
}
if (match) {
//将不同类型的 Advisor 转换成对应类型的 MethodInterceptor,目的是为了能在处理不同拦截器方法时能有同样的处理方式,可以理解为适配器模式。
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
//动态切点的isRuntime()方法会返回true,可以根据参数值来决定是否进行切入。一般都是自定义的切点才会执行这一块
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 {
// Spring AOP 根据注解生成的 Advisor 会走到这里
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;
}
//将Advisor转换为对应的拦截器类型
public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
List<MethodInterceptor> interceptors = new ArrayList<>(3);
Advice advice = advisor.getAdvice();
if (advice instanceof MethodInterceptor) {
interceptors.add((MethodInterceptor) advice);
}
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]);
}
//这里可以看一下adpters是什么
private final List<AdvisorAdapter> adapters = new ArrayList<>(3);
/**
* Create a new DefaultAdvisorAdapterRegistry, registering well-known adapters.
*/
public DefaultAdvisorAdapterRegistry() {
registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
registerAdvisorAdapter(new AfterReturningAdviceAdapter());
registerAdvisorAdapter(new ThrowsAdviceAdapter());
}
public void registerAdvisorAdapter(AdvisorAdapter adapter) {
this.adapters.add(adapter);
}
//通过上面这几段代码可以看出来,他就是一个塞进三个adpater实例的列表,这三个实例的处理方式是一样的,都是获取到 Advice ,然后给他封装一下返回。此外注意,@After 并没有转换因为AspectJAfterAdvice 本来就是拦截器类型的,它已经有了invoke方法了。AspectJAfterThrowingAdvice也是没有转换。以MethodBeforeAdviceAdapter为例讲一下怎么转换的。
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);
}
}
//通过调用构造函数,封装的拦截器实例就构造好了,它现在也有invoke方法了,和其它自定义的方法,代理对象的执行方法现在已经保持一致了,如此才可以放入一个拦截器列表里用同样的方式执行。
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
public Object invoke(MethodInvocation mi) throws Throwable {
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
return mi.proceed();
}
}
这里就获取到了跟当前被代理对象执行某个方法时所需要的所有的 Advisor,总结一下就是在生成代理对象的时候,匹配到了当前代理对象所需的所有的 Advisor, 具体执行某个方法的时候还需要在这么多 Advisor 中找到增强当前方法的 Advisor。此外,如果Advice没有invoke方法,为了方便统一处理,找到之后还会把 Advisor 中的 Advice 抽出来封装成跟代理对象一样都拥有invke方法的拦截器实例。但是 AspectJAfterThrowingAdvice 和 AspectJAfterAdvice 因为已经有了invoke方法了,所以就不用转换了。。下面继续看一下拦截器链具体怎么执行的。
public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
//当拦截器方法调用完了之后才调用被增强的方法
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
//从拦截器链中获取拦截器。该方法是递归调用,每次进入该方法都会进行将下标+1,获取到下一个拦截器。
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;
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.
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);
}
}
总结一下上面这个方法的流程。每次进入该方法都会通过下标获取到一个拦截器。然后调用invoke方法执行对应拦截器的invoke方法。然后在拦截器的方法中又回调用proceed方法返回到当前方法中。然后下标+1,取到下一个拦截器继续执行,直到拦截器链中的拦截器全部执行完才算结束。那么现在有一个问题,比如当前的方法同时被 @Before, @After, @AfterReturning, @AfterThrowing 同时增强。那么执行顺序是什么呢?这里先直接揭晓答案,后面再将这个顺序什么时候确定的。执行顺序为 before->after->afterReturning->afterThrowing,其中@Before对应的拦截器为MethodBeforeAdviceInterceptor,@After->AspectJAfterAdvice,@AfterReturning->AfterReturningAdviceInterceptor,@AfterThrowing->AspectJAfterThrowingAdvice。先看一下各个拦截器的invoke方法
//MethodBeforeAdviceInterceptor:
public Object invoke(MethodInvocation mi) throws Throwable {
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
return mi.proceed();
}
//AspectJAfterAdvice
public Object invoke(MethodInvocation mi) throws Throwable {
try {
return mi.proceed();
}
finally {
invokeAdviceMethod(getJoinPointMatch(), null, null);
}
}
//AfterReturningAdviceInterceptor
public Object invoke(MethodInvocation mi) throws Throwable {
Object retVal = mi.proceed();
this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
return retVal;
}
//AspectJAfterThrowingAdvice
public Object invoke(MethodInvocation mi) throws Throwable {
try {
return mi.proceed();
}
catch (Throwable ex) {
if (shouldInvokeOnThrowing(ex)) {
invokeAdviceMethod(getJoinPointMatch(), null, ex);
}
throw ex;
}
}
通过递归调用,这些拦截器会按照顺序一个一个执行,抛弃递归可以简化为如下过程
//执行 @Before 的通知方法
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
try {
try {
//执行目标方法
return invokeJoinpoint();
} catch (Throwable ex) {
if (shouldInvokeOnThrowing(ex)) {
//执行 @AfterThrowing 的通知方法
invokeAdviceMethod(getJoinPointMatch(), null, ex);
}
throw ex;
}
//执行 @AfterReturning 的通知方法
this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
} finally {
//执行 @After 的通知方法
invokeAdviceMethod(getJoinPointMatch(), null, null);
}
第一篇文章的时候通过跑样例代码已经得到了各个通知的执行顺序。这里通过源码可以再分析一下,那就是 @Before 一定会执行,然后就会执行目标方法,如果目标方法出错,会执行 @AfterThrowing 通知,同时抛出异常,并不会执行 @AfterReturning 通知。而如果目标方法没有报错,就不会执行 @AfterThrowing 通知了,接着会执行 @AfterReturning 通知。最后 finally 块中执行 @After 通知。所以无论目标方法是否会出错,@After 通知都会执行。
一般 @Around 通知不会和上面几个通知一块使用。但是如果确实同时配置了,因为 @Around 通知只是把目标方法拿过来自己执行,然后在目标方法前后做一些事情,所以可以把目标方法和上述几个通知理解为是一个整体,给它取个名字叫目标模块,然后 @Around 所做的事情,也都是在目标模块前面或者后面做的。如下
@Around(value = "pointCut()")
public Object methodAround(ProceedingJoinPoint pdj) {
Object result = null;
System.out.println("调用目标模块前 @Around ");
try {
//目标模块
result = pdj.proceed();
} catch (Throwable ex) {
System.out.println("捕捉到异常信息:" + ex);
}
System.out.println("调用目标模块后 @Around ");
return result;
}
所以可以在 @Around 通知捕捉其它通知的异常。所以 @Around 的执行顺序一定是在前面目标模块之前执行的。但是通知先执行并不是代表 @Around 都执行完了再执行其他通知,@Around 中可以有一部分内容在目标模块之前执行,也可以有一部分在目标模块之后执行。
现在拦截器链的执行流程已经理清楚了,但是还有一点需要补充一下,那就是怎么由拦截器跳到我们自己写的通知方法里执行的呢?我们可以猜测一下,如果是 Interceptor 类型的拦截器,比如@Before通知,需要先获取到 Advice, 然后再获取到对应的通知方法,然后再通过反射调用我们自己写的通知方法。而如果本身就是Advice类型的拦截器, 比如 @After 通知,则省略了获取Advice 的这一步。这里拿 MethodBeforeAdviceInterceptor 举例吧
public Object invoke(MethodInvocation mi) throws Throwable {
//可以看到,首先是获取到了advice, 然后调用了advice的before方法
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
return mi.proceed();
}
// AspectJMethodBeforeAdvice 的 before 方法
public void before(Method method, Object[] args, @Nullable Object target) throws Throwable {
//第一个参数为获取切点信息
invokeAdviceMethod(getJoinPointMatch(), null, null);
}
protected Object invokeAdviceMethod(
@Nullable JoinPointMatch jpMatch, @Nullable Object returnValue, @Nullable Throwable ex)
throws Throwable {
//第一个参数是获取目标方法的参数信息,然后传入该方法准备执行
return invokeAdviceMethodWithGivenArgs(argBinding(getJoinPoint(), jpMatch, returnValue, ex));
}
protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable {
//获取参数
Object[] actualArgs = args;
if (this.aspectJAdviceMethod.getParameterCount() == 0) {
actualArgs = null;
}
try {
ReflectionUtils.makeAccessible(this.aspectJAdviceMethod);
// TODO AopUtils.invokeJoinpointUsingReflection
//通过反射执行通知方法,这样就跳到我们自己手写的通知方法里去了
return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs);
}
catch (IllegalArgumentException ex) {
throw new AopInvocationException("Mismatch on arguments to advice method [" +
this.aspectJAdviceMethod + "]; pointcut expression [" +
this.pointcut.getPointcutExpression() + "]", ex);
}
catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
}
跳转到自己手写的通知方法的逻辑也讲完了。但是还是漏了一个重要的东西没有提到,我们再回到 AspectJMethodBeforeAdvice 的 before 方法。
public void before(Method method, Object[] args, @Nullable Object target) throws Throwable {
invokeAdviceMethod(getJoinPointMatch(), null, null);
}
可以看到它的三个参数分别问增强方法,参数和被代理对象。但是,后两个参数并没有用到,二是通过 getJoinPointMatch() 方法获取到连接点信息,然后再后面再通过连接点获取到参数信息。至于为什么这么操作,我理解可能是为了方便管理,也不用每个方法都带着这几个参数来回传,可是这就暴露出了一个问题,它怎么通过getJoinPointMatch() 方法,而且还没有传入任何参数,就能获取到连接点信息了呢?我们跟进一下这个方法,
protected JoinPointMatch getJoinPointMatch() {
//可以看到获取到了我们前面准备调用拦截器链方法时实例化的方法启动器。这个是通过拦截器链和被代理对象的包装类实例,在调用拦截器链方法之前创建出来的,大家如果不记得的话可以回到动态代理对象的 invoke 方法再看一下,所以通过它肯定是可以获取到连接点相关信息的。
MethodInvocation mi = ExposeInvocationInterceptor.currentInvocation();
if (!(mi instanceof ProxyMethodInvocation)) {
throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
}
return getJoinPointMatch((ProxyMethodInvocation) mi);
}
public static MethodInvocation currentInvocation() throws IllegalStateException {
// invocation 是一个 ThreadLocal<MethodInvocation> 变量,这里能直接获取说明前面在某个时间点被set进去了。
MethodInvocation mi = invocation.get();
if (mi == null) {
throw new IllegalStateException(
"No MethodInvocation found: Check that an AOP invocation is in progress and that the " +
"ExposeInvocationInterceptor is upfront in the interceptor chain. Specifically, note that " +
"advices with order HIGHEST_PRECEDENCE will execute before ExposeInvocationInterceptor! " +
"In addition, ExposeInvocationInterceptor and ExposeInvocationInterceptor.currentInvocation() " +
"must be invoked from the same thread.");
}
return mi;
}
可以看到有一个 ThreadLocal<MethodInvocation> 类型的变量存储了方法启动器MethodInvocation,而且是通过 ExposeInvocationInterceptor 获取到的,可是它什么时候存的呢我们却不知道。此外还记不记得上面我们讲了拦截器和目标方法的执行流程,可是具体执行顺序是我开了天眼就确定说好的。可是为什么拦截器就会按照那么顺序执行呢?什么时候对拦截器进行了排序呢?这就是我们剩下的两个问题了。
ExposeInvocationInterceptor
首先解决第一个问题,我们知道 ExposeInvocationInterceptor 中有 ThreadLocal<MethodInvocation> invocation 实例,它里面存着方法启动器信息,因为它是一个拦截器,那么就看一下它的 invoke 方法
public Object invoke(MethodInvocation mi) throws Throwable {
MethodInvocation oldInvocation = invocation.get();
//可以看到在这里就将方法启动器给保存起来了
invocation.set(mi);
try {
return mi.proceed();
}
finally {
invocation.set(oldInvocation);
}
}
那么我们可以把它放到代理对象拦截器链的第一个,让他的invoke方法先执行,那么后面的拦截器就可以通过 invocation 获取到方法启动器了。那么就回到获取被代理对象获取与之匹配的advisors 数组那里再看一看是不是干了这件事。
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
List<Advisor> candidateAdvisors = findCandidateAdvisors();
//这里是获取跟当前bean匹配的advisor
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
//注意这个方法,扩展advisors,跟进看一下它是怎么扩展的
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
//这个排序是根据拦截器指定的 Order 排序的,跟我们通过注解生成的拦截器还没关系,我们注解生成的拦截器数组,在解析切面的时候就就已经把切面方法给排好序了
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
protected void extendAdvisors(List<Advisor> candidateAdvisors) {
AspectJProxyUtils.makeAdvisorChainAspectJCapableIfNecessary(candidateAdvisors);
}
public static boolean makeAdvisorChainAspectJCapableIfNecessary(List<Advisor> advisors) {
// Don't add advisors to an empty list; may indicate that proxying is just not required
if (!advisors.isEmpty()) {
boolean foundAspectJAdvice = false;
for (Advisor advisor : advisors) {
// Be careful not to get the Advice without a guard, as this might eagerly
// instantiate a non-singleton AspectJ aspect...
if (isAspectJAdvice(advisor)) {
foundAspectJAdvice = true;
break;
}
}
//真相大白,确实是在匹配的advisors数组的最前面设置了ExposeInvocationInterceptor 类型的 advisor
if (foundAspectJAdvice && !advisors.contains(ExposeInvocationInterceptor.ADVISOR)) {
advisors.add(0, ExposeInvocationInterceptor.ADVISOR);
return true;
}
}
return false;
}
综上所述,在获取到bean匹配的advisor数组之后,还在数组最前面给它添加了一个ExposeInvocationInterceptor 类型的advisor, 这样执行拦截器链时就会先执行这个拦截器,进而把MethodInvovation 给保存起来,后面的拦截器就可以使用了。
各个通知的执行顺序
最后一个要探讨的问题时,advisor 什么时候排序的呢?怎么就按照我们上面说的那样以此执行了呢?这时候要回到获取 advisor 数组的时候了。
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
validate(aspectClass);
// We need to wrap the MetadataAwareAspectInstanceFactory with a decorator
// so that it will only instantiate once.
MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);
List<Advisor> advisors = new ArrayList<>();
//这里是解析切面的方法,然后生成一个个advisor,有序的放入advisors数组,那么说明getAdvisorMethods()已经获取到有序的方法了。只有这样生成的advisor才是有序的。
for (Method method : getAdvisorMethods(aspectClass)) {
// Prior to Spring Framework 5.2.7, advisors.size() was supplied as the declarationOrderInAspect
// to getAdvisor(...) to represent the "current position" in the declared methods list.
// However, since Java 7 the "current position" is not valid since the JDK no longer
// returns declared methods in the order in which they are declared in the source code.
// Thus, we now hard code the declarationOrderInAspect to 0 for all advice methods
// discovered via reflection in order to support reliable advice ordering across JVM launches.
// Specifically, a value of 0 aligns with the default value used in
// AspectJPrecedenceComparator.getAspectDeclarationOrder(Advisor).
Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 0, aspectName);
if (advisor != null) {
advisors.add(advisor);
}
}
// If it's a per target aspect, emit the dummy instantiating aspect.
if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
advisors.add(0, instantiationAdvisor);
}
// Find introduction fields.
for (Field field : aspectClass.getDeclaredFields()) {
Advisor advisor = getDeclareParentsAdvisor(field);
if (advisor != null) {
advisors.add(advisor);
}
}
return advisors;
}
private List<Method> getAdvisorMethods(Class<?> aspectClass) {
final List<Method> methods = new ArrayList<>();
ReflectionUtils.doWithMethods(aspectClass, method -> {
// Exclude pointcuts
if (AnnotationUtils.getAnnotation(method, Pointcut.class) == null) {
methods.add(method);
}
}, ReflectionUtils.USER_DECLARED_METHODS);
if (methods.size() > 1) {
//这里对方法进行排序
methods.sort(METHOD_COMPARATOR);
}
return methods;
}
由上可以看出,解析切面的时候,对切面的方法就进行排序了,所以切面方法生成的advisor也是有序的。那么就看一下怎么对切面方法进行排序的。看一下 METHOD_COMPARATOR
//方法的排序比较器
private static final Comparator<Method> METHOD_COMPARATOR;
static {
// Note: although @After is ordered before @AfterReturning and @AfterThrowing,
// an @After advice method will actually be invoked after @AfterReturning and
// @AfterThrowing methods due to the fact that AspectJAfterAdvice.invoke(MethodInvocation)
// invokes proceed() in a `try` block and only invokes the @After advice method
// in a corresponding `finally` block.
Comparator<Method> adviceKindComparator = new ConvertingComparator<>(
//这里定义了排序的顺序规则
new InstanceComparator<>(
Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class),
(Converter<Method, Annotation>) method -> {
AspectJAnnotation<?> ann = AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(method);
return (ann != null ? ann.getAnnotation() : null);
});
Comparator<Method> methodNameComparator = new ConvertingComparator<>(Method::getName);
//定义排序比较器规则
METHOD_COMPARATOR = adviceKindComparator.thenComparing(methodNameComparator);
}
可以看到排序比较器定义了注解内容的排序顺序,Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class, 这样就跟前面全部串联起来了。