Async是Spring新加入的一种异步机制, 大多开发者也只是停留在会用的水平, 对其原理不太了解, 作为一名开发人员, 我们不仅要知其然, 更要知其所以然, 才能在项目开发过程中不会踩到不必要的坑.
用法
1.在SpringBoot启动类添加注解@EnableAsync
@EnableAsync
@SpringBootApplication
public class WebApplication {
public static void main(String[] args) {
SpringApplication.run(WebApplication.class, args);
}
}
2.添加线程池执行器
@Configuration
public class WebConfiguration implements WebMvcConfigurer {
@Bean("asyncThreadExecutor")
public Executor asyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(10);
executor.setKeepAliveSeconds(30);
executor.setQueueCapacity(1000);
return null;
}
}
3.方法添加注解@Async
@Service
public class AsyncServiceImpl implements AsyncService {
@Override
@Async("asyncThreadExecutor")
public void asyncTest() {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("-------Async------");
}
}
4.使用Controller测试
@RestController
public class AsyncController {
@Autowired
private AsyncService asyncService;
@RequestMapping("/async/test")
public Object async() {
asyncService.asyncTest();
System.out.println("---------main--------");
return "success";
}
}
5.测试
---------main--------
-------Async------
源码解析
1.注解类EnableAsync
使用Import导入Async配置注册类
org.springframework.scheduling.annotation.EnableAsync
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AsyncConfigurationSelector.class)
public @interface EnableAsync {
...
AdviceMode mode() default AdviceMode.PROXY;
...
}
2.配置类AsyncConfigurationSelector
使用Spring ImportSelector方式向Spring中添加class为ProxyAsyncConfiguration的BeanDefinition, 后期会对其进行实例化
org.springframework.scheduling.annotation.AsyncConfigurationSelector
public class AsyncConfigurationSelector extends AdviceModeImportSelector<EnableAsync> {
private static final String ASYNC_EXECUTION_ASPECT_CONFIGURATION_CLASS_NAME =
"org.springframework.scheduling.aspectj.AspectJAsyncConfiguration";
@Override
@Nullable
public String[] selectImports(AdviceMode adviceMode) {
switch (adviceMode) {
case PROXY: // 默认使用代理方式
return new String[] {ProxyAsyncConfiguration.class.getName()};
case ASPECTJ:
return new String[] {ASYNC_EXECUTION_ASPECT_CONFIGURATION_CLASS_NAME};
default:
return null;
}
}
}
3.代理配置类ProxyAsyncConfiguration
添加了@Configuration注解, 并注入了Bean AsyncAnnotationBeanPostProcessor
org.springframework.scheduling.annotation.ProxyAsyncConfiguration
@Configuration
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class ProxyAsyncConfiguration extends AbstractAsyncConfiguration {
@Bean(name = TaskManagementConfigUtils.ASYNC_ANNOTATION_PROCESSOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public AsyncAnnotationBeanPostProcessor asyncAdvisor() {
Assert.notNull(this.enableAsync, "@EnableAsync annotation metadata was not injected");
// 返回AsyncAnnotationBeanPostProcessor对象
// 向容器中注入AsyncAnnotationBeanPostProcessor后置处理器对象
AsyncAnnotationBeanPostProcessor bpp = new AsyncAnnotationBeanPostProcessor();
// 配置线程池和异常处理器
bpp.configure(this.executor, this.exceptionHandler);
// 获取注解的属性添加到对象中
Class<? extends Annotation> customAsyncAnnotation = this.enableAsync.getClass("annotation");
if (customAsyncAnnotation != AnnotationUtils.getDefaultValue(EnableAsync.class, "annotation")) {
bpp.setAsyncAnnotationType(customAsyncAnnotation);
}
bpp.setProxyTargetClass(this.enableAsync.getBoolean("proxyTargetClass"));
bpp.setOrder(this.enableAsync.<Integer>getNumber("order"));
return bpp;
}
}
4.AsyncAnnotationBeanPostProcessor
后置处理器, 父类实现了BeanPostProcessor, 内部重要方法postProcessAfterInitialization()
AsyncAnnotationBeanPostProcessor 父类实现了BeanFactoryAware接口, 在bean初始化后会调用setBeanFactory()
org.springframework.scheduling.annotation.AsyncAnnotationBeanPostProcessor
public class AsyncAnnotationBeanPostProcessor extends AbstractBeanFactoryAwareAdvisingPostProcessor {
...
@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;
}
}
5.AsyncAnnotationAdvisor构造方法
org.springframework.scheduling.annotation.AsyncAnnotationAdvisor#AsyncAnnotationAdvisor
public AsyncAnnotationAdvisor(
@Nullable Supplier<Executor> executor, @Nullable Supplier<AsyncUncaughtExceptionHandler> exceptionHandler) {
Set<Class<? extends Annotation>> asyncAnnotationTypes = new LinkedHashSet<>(2);
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.
}
// 保存methodInterceptor 调用方法时会执行
this.advice = buildAdvice(executor, exceptionHandler);
this.pointcut = buildPointcut(asyncAnnotationTypes);
}
6.AnnotationAsyncExecutionInterceptor
AnnotationAsyncExecutionInterceptor 父类实现了MethodInterceptor, 后期调用代理对象方法时会执行此类中的方法 稍后分析AnnotationAsyncExecutionInterceptor.invoke()方法
org.springframework.scheduling.annotation.AsyncAnnotationAdvisor#buildAdvice
protected Advice buildAdvice(
@Nullable Supplier<Executor> executor, @Nullable Supplier<AsyncUncaughtExceptionHandler> exceptionHandler) {
AnnotationAsyncExecutionInterceptor interceptor = new AnnotationAsyncExecutionInterceptor(null);
interceptor.configure(executor, exceptionHandler);
return interceptor;
}
Spring在bean初始化后会调用此方法postProcessAfterInitialization()
org.springframework.aop.framework.AbstractAdvisingBeanPostProcessor
public abstract class AbstractAdvisingBeanPostProcessor extends ProxyProcessorSupport implements BeanPostProcessor {
@Nullable
protected Advisor advisor;
protected boolean beforeExistingAdvisors = false;
private final Map<Class<?>, Boolean> eligibleBeans = new ConcurrentHashMap<>(256);
...
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (this.advisor == null || bean instanceof AopInfrastructureBean) {
// Ignore AOP infrastructure such as scoped proxies.
return bean;
}
// 判断bean是否已经被代理 如果bean内有Async和Transactional注解会执行此方法
if (bean instanceof Advised) {
Advised advised = (Advised) bean;
if (!advised.isFrozen() && isEligible(AopUtils.getTargetClass(bean))) {
// Add our local Advisor to the existing proxy's Advisor chain...
if (this.beforeExistingAdvisors) {
advised.addAdvisor(0, this.advisor);
}
else {
advised.addAdvisor(this.advisor);
}
return bean;
}
}
// 判断bean中的方法是否有Async注解方法
if (isEligible(bean, beanName)) {
// 为bean添加一个简单工厂
ProxyFactory proxyFactory = prepareProxyFactory(bean, beanName);
if (!proxyFactory.isProxyTargetClass()) {
evaluateProxyInterfaces(bean.getClass(), proxyFactory);
}
proxyFactory.addAdvisor(this.advisor);
// 空方法
customizeProxyFactory(proxyFactory);
// 创建代理
return proxyFactory.getProxy(getProxyClassLoader());
}
// No proxy needed.
return bean;
}
protected boolean isEligible(Object bean, String beanName) {
return isEligible(bean.getClass());
}
protected boolean isEligible(Class<?> targetClass) {
Boolean eligible = this.eligibleBeans.get(targetClass);
if (eligible != null) {
return eligible;
}
if (this.advisor == null) {
return false;
}
// 利用反射获取bean的各方法, 并判断是否有Async注解
eligible = AopUtils.canApply(this.advisor, targetClass);
this.eligibleBeans.put(targetClass, eligible);
return eligible;
}
protected ProxyFactory prepareProxyFactory(Object bean, String beanName) {
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
proxyFactory.setTarget(bean);
return proxyFactory;
}
...
}
org.springframework.aop.framework.ProxyFactory#getProxy(java.lang.ClassLoader)
public Object getProxy(@Nullable ClassLoader classLoader) {
return createAopProxy().getProxy(classLoader);
}
先分析createAopProxy()方法, 稍后分析getProxy()方法
org.springframework.aop.framework.ProxyCreatorSupport#createAopProxy
protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
activate();
}
return getAopProxyFactory().createAopProxy(this);
}
org.springframework.aop.framework.DefaultAopProxyFactory#createAopProxy
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
Class<?> targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: " +
"Either an interface or a target is required for proxy creation.");
}
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
// 判断未实现接口 使用CGLib代理
return new ObjenesisCglibAopProxy(config);
}
else {
// 实现了接口使用JDK代理
return new JdkDynamicAopProxy(config);
}
}
getProxy()方法
共实现了4个接口
com.ansheng.web.service.AsyncService
org.springframework.aop.SpringProxy
org.springframework.aop.framework.Advised
org.springframework.core.DecoratingProxy
JdkDynamicAopProxy实现了InvocationHandler, 生成代理对象, 调用目标对象的方法时, 会调用产生代理对象的invoke方法
org.springframework.aop.framework.JdkDynamicAopProxy
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {
...
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isTraceEnabled()) {
logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
}
// 获取代理应该实现的接口
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
...
@Override
@Nullable
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
...
// Get the interception chain for this method.
// 根据方法获取方法调用链, 内部使用Map存储, 提高执行效率 默认只有一个 之前提到的methodInterceptor AnnotationAsyncExecutionInterceptor对象
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;
...
}
...
}
7.异步方法调用
先执行 org.springframework.aop.framework.JdkDynamicAopProxy.invoke() 方法, 然后执行AnnotationAsyncExecutionInterceptor.invoke()方法
org.springframework.scheduling.annotation.AnnotationAsyncExecutionInterceptor
public Object invoke(final MethodInvocation invocation) throws Throwable {
// 目标类
Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
// 目标对象要执行的方法
Method specificMethod = ClassUtils.getMostSpecificMethod(invocation.getMethod(), targetClass);
final Method userDeclaredMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
// 获取对应的线程池执行器
AsyncTaskExecutor executor = determineAsyncExecutor(userDeclaredMethod);
if (executor == null) {
throw new IllegalStateException(
"No executor specified and no default executor set on AsyncExecutionInterceptor either");
}
// 使用Callable创建线程
Callable<Object> task = () -> {
try {
Object result = invocation.proceed();
if (result instanceof Future) {
return ((Future<?>) result).get();
}
}
catch (ExecutionException ex) {
handleError(ex.getCause(), userDeclaredMethod, invocation.getArguments());
}
catch (Throwable ex) {
handleError(ex, userDeclaredMethod, invocation.getArguments());
}
return null;
};
// 添加到线程池执行器中
return doSubmit(task, executor, invocation.getMethod().getReturnType());
}
通过方法注解获取线程池beanName
org.springframework.aop.interceptor.AsyncExecutionAspectSupport#determineAsyncExecutor
protected AsyncTaskExecutor determineAsyncExecutor(Method method) {
AsyncTaskExecutor executor = this.executors.get(method);
if (executor == null) {
Executor targetExecutor;
String qualifier = getExecutorQualifier(method);
if (StringUtils.hasLength(qualifier)) {
// 有设置bean则根据beanName查找线程池
targetExecutor = findQualifiedExecutor(this.beanFactory, qualifier);
}
else {
// 如果没有设置执行器名称, 就通过类型去寻找
// SpringBoot默认开启了自动配置 配置文件路径
// spring-boot-test-autoconfigure\2.3.0.RELEASE\spring-boot-test-autoconfigure-2.3.0.RELEASE.jar!\META-INF\spring.factories
// 配置文件默认装载了bean -> org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration
// 所以如果没有在启动类上有排除, 则会使用TaskExecutionAutoConfiguration @SpringBootApplication(exclude = {TaskExecutionAutoConfiguration.class})
// 如果设置了不状态默认执行器, 则new SimpleAsyncTaskExecutor()作为默认执行器
targetExecutor = this.defaultExecutor.get();
}
if (targetExecutor == null) {
return null;
}
executor = (targetExecutor instanceof AsyncListenableTaskExecutor ?
(AsyncListenableTaskExecutor) targetExecutor : new TaskExecutorAdapter(targetExecutor));
this.executors.put(method, executor);
}
return executor;
}
TaskExecutionAutoConfiguration
是一个配置类, 注入一个TaskExecutor, 默认配置如图
org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration
@ConditionalOnClass(ThreadPoolTaskExecutor.class)
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(TaskExecutionProperties.class)
public class TaskExecutionAutoConfiguration {
/**
* Bean name of the application {@link TaskExecutor}.
*/
public static final String APPLICATION_TASK_EXECUTOR_BEAN_NAME = "applicationTaskExecutor";
@Bean
@ConditionalOnMissingBean
public TaskExecutorBuilder taskExecutorBuilder(TaskExecutionProperties properties,
ObjectProvider<TaskExecutorCustomizer> taskExecutorCustomizers,
ObjectProvider<TaskDecorator> taskDecorator) {
TaskExecutionProperties.Pool pool = properties.getPool();
TaskExecutorBuilder builder = new TaskExecutorBuilder();
builder = builder.queueCapacity(pool.getQueueCapacity());
builder = builder.corePoolSize(pool.getCoreSize());
builder = builder.maxPoolSize(pool.getMaxSize());
builder = builder.allowCoreThreadTimeOut(pool.isAllowCoreThreadTimeout());
builder = builder.keepAlive(pool.getKeepAlive());
Shutdown shutdown = properties.getShutdown();
builder = builder.awaitTermination(shutdown.isAwaitTermination());
builder = builder.awaitTerminationPeriod(shutdown.getAwaitTerminationPeriod());
builder = builder.threadNamePrefix(properties.getThreadNamePrefix());
builder = builder.customizers(taskExecutorCustomizers.orderedStream()::iterator);
builder = builder.taskDecorator(taskDecorator.getIfUnique());
return builder;
}
@Lazy
@Bean(name = { APPLICATION_TASK_EXECUTOR_BEAN_NAME,
AsyncAnnotationBeanPostProcessor.DEFAULT_TASK_EXECUTOR_BEAN_NAME })
@ConditionalOnMissingBean(Executor.class)
public ThreadPoolTaskExecutor applicationTaskExecutor(TaskExecutorBuilder builder) {
return builder.build();
}
}
doSubmit() 方法如果返回类型为CompletableFuture / ListenableFuture / Future三种类型作为返回类型时, 会在执行完成后返回结果, 否则直接异步执行并返回null
org.springframework.aop.interceptor.AsyncExecutionAspectSupport#doSubmit
protected Object doSubmit(Callable<Object> task, AsyncTaskExecutor executor, Class<?> returnType) {
if (CompletableFuture.class.isAssignableFrom(returnType)) {
return CompletableFuture.supplyAsync(() -> {
try {
return task.call();
}
catch (Throwable ex) {
throw new CompletionException(ex);
}
}, executor);
}
else if (ListenableFuture.class.isAssignableFrom(returnType)) {
return ((AsyncListenableTaskExecutor) executor).submitListenable(task);
}
else if (Future.class.isAssignableFrom(returnType)) {
return executor.submit(task);
}
else {
executor.submit(task);
return null;
}
}
总结
Async 通过使用Spring的ImportSelector方法, 向Spring中注册了一个Configuration配置类, 并且注入了一个BeanPostProcessor, 在bean实例化后调用postProcessAfterInitialization方法, 为对象产生动态代理(如果目标类实现了接口, 默认使用JDK代理, 否则使用CGLib)
执行异步方法时, 调用JdkDynamicAopProxy.invoke()方法, 获取调用链并执行AnnotationAsyncExecutionInterceptor.invoke()方法, 然后根据方法注解获取线程池执行器, 创建并submit线程,
如果有Feture类型返回对象, 等执行完成后返回结果, 否则异步调用并直接返回null
错误使用
类内部直接调用不会生效
使用Async的类,如果产生循环依赖(A->A; A->B, B->A)无法解决
原因
由于Async使用动态代理实现, 所以类内部直接调用没有使用动态代理, 所以不会生效, 这一点和@Transactional注解原理类似,但又不完全一样
@Async产生代理的时机是在bean初始化完成后AbstractAdvisingBeanPostProcessor.postProcessAfterInitialization方法内实现 @Transactional是在实例化之后立即被代理,其他对象可以直接引用到当前对象的早期依赖.
解决方法
1.类内部注入自己,添加@Lazy注解
@Lazy
@Autowired
private AsyncService asyncService;
2.通过实现BeanFactoryAware结果, 获取到BeanFactory后, 从容器中再次获取代理对象, 然后调用方法
@Service
public class AsyncServiceImpl implements AsyncService, ApplicationContextAware {
private ApplicationContext ac;
@Override
@Async("asyncExecutor")
public void processAsync(int index) {
...
}
@Override
public void inLazy(int index) {
ac.getBean(AsyncService.class).processAsync(2);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.ac = applicationContext;
}
}
3.将方法移到其他类中, 通过注入bean完成调用
4.不用默认代理模式,使用Aspectj加载时织入完成异步
引入包
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</dependency>
启动类指定mode AspectJ
@EnableAsync(mode = AdviceMode.ASPECTJ)
添加启动参数 指定agent
-javaagent:C:\Users\GuanDS.m2\repository\org\aspectj\aspectjweaver\1.9.2\aspectjweaver-1.9.2.jar