@EnableAsync+@Async源码学习笔记之四
接上一篇,我们进入 AsyncAnnotationAdvisor
的分析,源码如下:
package org.springframework.scheduling.annotation;import java.lang.annotation.Annotation;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.concurrent.Executor;import org.aopalliance.aop.Advice;import org.springframework.aop.Pointcut;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.aop.interceptor.SimpleAsyncUncaughtExceptionHandler;
import org.springframework.aop.support.AbstractPointcutAdvisor;
import org.springframework.aop.support.ComposablePointcut;
import org.springframework.aop.support.annotation.AnnotationMatchingPointcut;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;/*** Advisor that activates asynchronous method execution through the {@link Async}* annotation. This annotation can be used at the method and type level in* implementation classes as well as in service interfaces.** <p>This advisor detects the EJB 3.1 {@code javax.ejb.Asynchronous}* annotation as well, treating it exactly like Spring's own {@code Async}.* Furthermore, a custom async annotation type may get specified through the* {@link #setAsyncAnnotationType "asyncAnnotationType"} property.** @author Juergen Hoeller* @since 3.0* @see Async* @see AnnotationAsyncExecutionInterceptor*/
@SuppressWarnings("serial")
public class AsyncAnnotationAdvisor extends AbstractPointcutAdvisor implements BeanFactoryAware {private AsyncUncaughtExceptionHandler exceptionHandler;private Advice advice;private Pointcut pointcut;/*** Create a new {@code AsyncAnnotationAdvisor} for bean-style configuration.*/public AsyncAnnotationAdvisor() {this(null, null);}/*** Create a new {@code AsyncAnnotationAdvisor} for the given task executor.* @param executor the task executor to use for asynchronous methods* (can be {@code null} to trigger default executor resolution)* @param exceptionHandler the {@link AsyncUncaughtExceptionHandler} to use to* handle unexpected exception thrown by asynchronous method executions* @see AnnotationAsyncExecutionInterceptor#getDefaultExecutor(BeanFactory)*/@SuppressWarnings("unchecked")public AsyncAnnotationAdvisor(@Nullable Executor executor, @Nullable AsyncUncaughtExceptionHandler exceptionHandler) {Set<Class<? extends Annotation>> asyncAnnotationTypes = new LinkedHashSet<>(2);System.out.println("默认支持spring的Async注解和EJB的javax.ejb.Asynchronous");asyncAnnotationTypes.add(Async.class);try {asyncAnnotationTypes.add((Class<? extends Annotation>)ClassUtils.forName("javax.ejb.Asynchronous", AsyncAnnotationAdvisor.class.getClassLoader()));}catch (ClassNotFoundException ex) {// If EJB 3.1 API not present, simply ignore.}if (exceptionHandler != null) {this.exceptionHandler = exceptionHandler;}else {System.out.println("如果没有指定异常处理器的话,则用默认的异常处理器 SimpleAsyncUncaughtExceptionHandler ");System.out.println("默认的异常处理器 SimpleAsyncUncaughtExceptionHandler 所做的事情就是把异常打印到日志里边 ");this.exceptionHandler = new SimpleAsyncUncaughtExceptionHandler();}// 构造通知和切点this.advice = buildAdvice(executor, this.exceptionHandler);this.pointcut = buildPointcut(asyncAnnotationTypes);}/*** Specify the default task executor to use for asynchronous methods.*/public void setTaskExecutor(Executor executor) {this.advice = buildAdvice(executor, this.exceptionHandler);}/*** Set the 'async' annotation type.* <p>The default async annotation type is the {@link Async} annotation, as well* as the EJB 3.1 {@code javax.ejb.Asynchronous} annotation (if present).* <p>This setter property exists so that developers can provide their own* (non-Spring-specific) annotation type to indicate that a method is to* be executed asynchronously.* @param asyncAnnotationType the desired annotation type*/public void setAsyncAnnotationType(Class<? extends Annotation> asyncAnnotationType) {Assert.notNull(asyncAnnotationType, "'asyncAnnotationType' must not be null");Set<Class<? extends Annotation>> asyncAnnotationTypes = new HashSet<>();asyncAnnotationTypes.add(asyncAnnotationType);this.pointcut = buildPointcut(asyncAnnotationTypes);}/*** Set the {@code BeanFactory} to be used when looking up executors by qualifier.*/@Overridepublic void setBeanFactory(BeanFactory beanFactory) {if (this.advice instanceof BeanFactoryAware) {((BeanFactoryAware) this.advice).setBeanFactory(beanFactory);}}@Overridepublic Advice getAdvice() {return this.advice;}@Overridepublic Pointcut getPointcut() {return this.pointcut;}protected Advice buildAdvice(@Nullable Executor executor, AsyncUncaughtExceptionHandler exceptionHandler) {return new AnnotationAsyncExecutionInterceptor(executor, exceptionHandler);}/*** Calculate a pointcut for the given async annotation types, if any.* @param asyncAnnotationTypes the async annotation types to introspect* @return the applicable Pointcut object, or {@code null} if none*/protected Pointcut buildPointcut(Set<Class<? extends Annotation>> asyncAnnotationTypes) {ComposablePointcut result = null;for (Class<? extends Annotation> asyncAnnotationType : asyncAnnotationTypes) {Pointcut cpc = new AnnotationMatchingPointcut(asyncAnnotationType, true);Pointcut mpc = new AnnotationMatchingPointcut(null, asyncAnnotationType, true);if (result == null) {result = new ComposablePointcut(cpc);}else {result.union(cpc);}result = result.union(mpc);}return (result != null ? result : Pointcut.TRUE);}
}
- 首先要关注的就是有2个参数的构造方法,也是上一篇文章最后提到的,有疑问可以看上一篇,调用的地方如下:
// 重点就是这个 AsyncAnnotationAdvisor
AsyncAnnotationAdvisor advisor = new AsyncAnnotationAdvisor(this.executor, this.exceptionHandler);
这个构造方法,第一步,用一个 Set
来存储 spring 的 @Async
注解和 EJB 的 @javax.ejb.Asynchronous
注解
Set<Class<? extends Annotation>> asyncAnnotationTypes = new LinkedHashSet<>(2);
System.out.println("默认支持spring的Async注解和EJB的javax.ejb.Asynchronous");
asyncAnnotationTypes.add(Async.class);
try {asyncAnnotationTypes.add((Class<? extends Annotation>)ClassUtils.forName("javax.ejb.Asynchronous", AsyncAnnotationAdvisor.class.getClassLoader()));
}
catch (ClassNotFoundException ex) {// If EJB 3.1 API not present, simply ignore.
}
构造方法的第二步,是对异常处理器的处理,代码如下:
if (exceptionHandler != null) {this.exceptionHandler = exceptionHandler;
}
else {System.out.println("如果没有指定异常处理器的话,则用默认的异常处理器 SimpleAsyncUncaughtExceptionHandler ");System.out.println("默认的异常处理器 SimpleAsyncUncaughtExceptionHandler 所做的事情就是把异常打印到日志里边 ");this.exceptionHandler = new SimpleAsyncUncaughtExceptionHandler();
}
如果入参给了异常处理器,就将入参的异常处理器赋值给成员变量,否则就用默认的SimpleAsyncUncaughtExceptionHandler
。
构造方法的第三步,构造通知和切点,代码如下:
this.advice = buildAdvice(executor, this.exceptionHandler);
this.pointcut = buildPointcut(asyncAnnotationTypes);
先看构造通知:
protected Advice buildAdvice(@Nullable Executor executor, AsyncUncaughtExceptionHandler exceptionHandler) {return new AnnotationAsyncExecutionInterceptor(executor, exceptionHandler);
}
其实就是new了一个拦截器AnnotationAsyncExecutionInterceptor
。
再看构造切点:
protected Pointcut buildPointcut(Set<Class<? extends Annotation>> asyncAnnotationTypes) {ComposablePointcut result = null;for (Class<? extends Annotation> asyncAnnotationType : asyncAnnotationTypes) {Pointcut cpc = new AnnotationMatchingPointcut(asyncAnnotationType, true);Pointcut mpc = new AnnotationMatchingPointcut(null, asyncAnnotationType, true);if (result == null) {result = new ComposablePointcut(cpc);}else {result.union(cpc);}result = result.union(mpc);}return (result != null ? result : Pointcut.TRUE);
}
这里边其实就是定位标记有 @Async
和 @javax.ejb.Asynchronous
的方法,也就是你写的异步方法,当然,不仅仅是这2个注解,还有你自定义的注解。
到这里有人可能会疑惑,我从构造方法一路追过来,入参中的 asyncAnnotationTypes 里边就俩值 @Async
和 @javax.ejb.Asynchronous
啊。
哪里还有我自定义的注解,不要着急,这个 buildPointcut
方法在 setAsyncAnnotationType
方法中被调用了一次,就是在那一次中,传入了你自定义的注解。
而 setAsyncAnnotationType
是在上文中讲的 AsyncAnnotationBeanPostProcessor
的 setBeanFactory
方法中被调用的,再看下:
@Override
public void setBeanFactory(BeanFactory beanFactory) {super.setBeanFactory(beanFactory);AsyncAnnotationAdvisor advisor = new AsyncAnnotationAdvisor(this.executor, this.exceptionHandler);if (this.asyncAnnotationType != null) {advisor.setAsyncAnnotationType(this.asyncAnnotationType);}advisor.setBeanFactory(beanFactory);this.advisor = advisor;
}
下面这几行代码,就解析了 @Async
和 @javax.ejb.Asynchronous
以及你自定义的异步注解。
第一行解析了 @Async
和 @javax.ejb.Asynchronous
。
第三行解析了你自定义的注解。
AsyncAnnotationAdvisor advisor = new AsyncAnnotationAdvisor(this.executor, this.exceptionHandler);
if (this.asyncAnnotationType != null) {advisor.setAsyncAnnotationType(this.asyncAnnotationType);
}
最后,总结下:本文讲了两个重点,一个是构造切点,一个是构造通知。构造切点,我们讲的比较细致了。构造切面,也就是拦截器 AnnotationAsyncExecutionInterceptor
我们下一篇讲。