Spring Boot源码简析 @EnableAsync

相关阅读

源码

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AsyncConfigurationSelector.class)
public @interface EnableAsync {

    // 自定义类/方法上的开启异步功能的注解类型
    // 默认支持@Async/@javax.ejb.Asynchronous,自定义后则不支持默认
    Class<? extends Annotation> annotation() default Annotation.class;

    // interface-based(false) or subclass-based(true)
    boolean proxyTargetClass() default false;

    // 代理模式,支持PROXY/ASPECTJ
    AdviceMode mode() default AdviceMode.PROXY;

    int order() default Ordered.LOWEST_PRECEDENCE;
}

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Async {

    // 指定执行器,写入执行器BeanName即可采用指定执行器去异步执行方法
    String value() default "";
}

配置

配合@Configuration使用,表示开启注解驱动的异步处理;

@Configuration
@EnableAsync
public class AppConfig {
}

默认地,Spring会搜索一个执行器实例用于实现异步执行方法,从以下类型中选择一个:

  1. 唯一的org.springframework.core.task.TaskExecutor实例;
  2. 名为"taskExecutor"的java.util.concurrent.Executor实例;
    如果以上两个都不存在,则提供一个org.springframework.core.task.SimpleAsyncTaskExecutor实例处理异步方法调用;
    用户可以实现接口org.springframework.scheduling.annotation.AsyncConfigurer来提供自定义java.util.concurrent.Executororg.springframework.aop.interceptor.AsyncUncaughtExceptionHandler实现;
@Configuration
@EnableAsync
public class AppConfig implements AsyncConfigurer {

    // 提供自定义执行器
    @Override
    public Executor getAsyncExecutor() {
         ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
         executor.setCorePoolSize(7);
         executor.setMaxPoolSize(42);
         executor.setQueueCapacity(11);
         executor.setThreadNamePrefix("MyExecutor-");
         executor.initialize();
         return executor;
    }

    // 提供自定义异常处理器
    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
         return new MyAsyncUncaughtExceptionHandler();
    }
}

如果只想自定义java.util.concurrent.Executor或者org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler,其它方法可以直接返回null,从而保持默认配置,此时可以考虑继承org.springframework.scheduling.annotation.AsyncConfigurerSupport

也可以定义多个执行器,在需要异步执行的方法上通过@Async注解value属性指定具体执行器的BeanName;

@Configuration
@EnableAsync
public class AsyncConfig {

    // 自定义执行器
    @Bean(name = "myExecutor")
    public Executor myExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(4);
        executor.setMaxPoolSize(8);
        executor.setQueueCapacity(100);
        executor.setKeepAliveSeconds(60);
        executor.setThreadNamePrefix("EXECUTOR");
        executor.initialize();
        return executor;
    }
}

public class Demo {

    // 指定具体执行器
    @Async(value = "myExecutor")
    public void method() {
        // do something
    }
}

简析

@EnableAsync注解通过Import机制引入AsyncConfigurationSelector

@Import(AsyncConfigurationSelector.class)

AsyncConfigurationSelector继承自AdviceModeImportSelectorAdviceModeImportSelector实现支持AdviceMode算法模板,且支持通用的@EnableXxx注解模式,代码如下:

public final String[] selectImports(AnnotationMetadata importingClassMetadata) {
    // 获取本类支持的注解类型
    // 对于AsyncConfigurationSelector来说为EnableAsync
    Class<?> annType = GenericTypeResolver.resolveTypeArgument(getClass(), AdviceModeImportSelector.class);
    Assert.state(annType != null, "Unresolvable type argument for AdviceModeImportSelector");

    // 获取注解属性数据
    AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType);
    if (attributes == null) {
        throw new IllegalArgumentException(String.format(
            "@%s is not present on importing class '%s' as expected",
            annType.getSimpleName(), importingClassMetadata.getClassName()));
    }

    // 获取注解的AdviceMode属性值
    AdviceMode adviceMode = attributes.getEnum(this.getAdviceModeAttributeName());
    // 根据AdviceMode获取引入配置类信息
    // 该方法由子类实现算法细节
    String[] imports = selectImports(adviceMode);
    if (imports == null) {
        throw new IllegalArgumentException(String.format("Unknown AdviceMode: '%s'", adviceMode));
    }
    return imports;
}

@Nullable
protected abstract String[] selectImports(AdviceMode adviceMode);

AsyncConfigurationSelector实现了算法细节selectImports,代码如下:

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;
    }
}

ProxyAsyncConfiguration

@EnableAsync的mode属性默认AdviceMode.PROXY,即引入了ProxyAsyncConfiguration
ProxyAsyncConfiguration继承自AbstractAsyncConfiguration,是一个配置类,其父类AbstractAsyncConfiguration实现了接口ImportAware,会注入@EnableAsync注解属性数据,且通过@Autowired注解注入AsyncConfigurer信息,代码如下:

public void setImportMetadata(AnnotationMetadata importMetadata) {
    // 注入@EnableAsync注解的属性数据
    this.enableAsync = AnnotationAttributes.fromMap(
            importMetadata.getAnnotationAttributes(EnableAsync.class.getName(), false));
    if (this.enableAsync == null) {
        throw new IllegalArgumentException(
                "@EnableAsync is not present on importing class " + importMetadata.getClassName());
    }
}

/**
 * Collect any {@link AsyncConfigurer} beans through autowiring.
 */
@Autowired(required = false)
void setConfigurers(Collection<AsyncConfigurer> configurers) {
    if (CollectionUtils.isEmpty(configurers)) {
        return;
    }
    // AsyncConfigurer bean只能存在一个
    if (configurers.size() > 1) {
        throw new IllegalStateException("Only one AsyncConfigurer may exist");
    }
    // 注入异步执行器和异常处理器
    AsyncConfigurer configurer = configurers.iterator().next();
    this.executor = configurer.getAsyncExecutor();
    this.exceptionHandler = configurer.getAsyncUncaughtExceptionHandler();
}

ProxyAsyncConfiguration配置AsyncAnnotationBeanPostProcessor Bean,代码如下:

@Bean(name = TaskManagementConfigUtils.ASYNC_ANNOTATION_PROCESSOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public AsyncAnnotationBeanPostProcessor asyncAdvisor() {
    // 校验@EnableAsync注解属性数据
    Assert.notNull(this.enableAsync, "@EnableAsync annotation metadata was not injected");
    AsyncAnnotationBeanPostProcessor bpp = new AsyncAnnotationBeanPostProcessor();
    // 获取开启异步功能的注解类型
    Class<? extends Annotation> customAsyncAnnotation = this.enableAsync.getClass("annotation");
    if (customAsyncAnnotation != AnnotationUtils.getDefaultValue(EnableAsync.class, "annotation")) {
        // 如果不是默认值,则使用自定义的值
        bpp.setAsyncAnnotationType(customAsyncAnnotation);
    }
    if (this.executor != null) {
        // 如果自定义执行器,则优先使用
        bpp.setExecutor(this.executor);
    }
    if (this.exceptionHandler != null) {
        // 如果自定义异常处理器,则优先使用
        bpp.setExceptionHandler(this.exceptionHandler);
    }
    bpp.setProxyTargetClass(this.enableAsync.getBoolean("proxyTargetClass"));
    bpp.setOrder(this.enableAsync.<Integer>getNumber("order"));
    return bpp;
}

AsyncAnnotationBeanPostProcessor

@EnableAsync注解最终引入了Bean后置处理器AsyncAnnotationBeanPostProcessor,毫无疑问,它会处理带有引发异步处理的注解(如:@Async)的Bean;
AsyncAnnotationBeanPostProcessor的继承层次中,AbstractAdvisingBeanPostProcessor实现了通用的Bean后置处理,代码如下:

public Object postProcessAfterInitialization(Object bean, String beanName) {
    if (bean instanceof AopInfrastructureBean || this.advisor == null) {
        // Ignore AOP infrastructure such as scoped proxies.
        return bean;
    }

    // 判断Bean是否已经被代理
    if (bean instanceof Advised) {
        // 已经被代理,则无需为其创建代理,直接添加Advisor
        Advised advised = (Advised) bean;
        // 判断当前Bean是否冻结,且合格
        if (!advised.isFrozen() && isEligible(AopUtils.getTargetClass(bean))) {
            // 满足要求后,则添加Advisor,即AsyncAnnotationAdvisor
            // 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是否合格
    if (isEligible(bean, beanName)) {
        // 合格则代理该Bean
        ProxyFactory proxyFactory = prepareProxyFactory(bean, beanName);
        if (!proxyFactory.isProxyTargetClass()) {
            evaluateProxyInterfaces(bean.getClass(), proxyFactory);
        }
        // 应用Advisor
        proxyFactory.addAdvisor(this.advisor);
        customizeProxyFactory(proxyFactory);
        return proxyFactory.getProxy(getProxyClassLoader());
    }

    // No async 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;
    }
    // 如果当前不存在Advisor则无需代理
    if (this.advisor == null) {
        return false;
    }
    // 当前的Advisor是否可以切入该targetClass
    eligible = AopUtils.canApply(this.advisor, targetClass);
    // 缓存结果,方便下次直接使用
    this.eligibleBeans.put(targetClass, eligible);
    return eligible;
}

AsyncAnnotationBeanPostProcessor会根据开启异步功能的注解类型、异步执行器、异常处理器生成切面AsyncAnnotationAdvisor,代码如下:

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;
}

AsyncAnnotationAdvisor

AsyncAnnotationAdvisor是一个PointcutAdvisor,且持有的Pointcut为聚合了AnnotationMatchingPointcutComposablePointcut,由此看出该切面用于处理注解;

public AsyncAnnotationAdvisor(@Nullable Executor executor, @Nullable AsyncUncaughtExceptionHandler exceptionHandler) {
    // 默认支持Async和javax.ejb.Asynchronous,故size为2
    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.
    }
    if (exceptionHandler != null) {
        // 设置自定义异常处理器,若存在的话
        this.exceptionHandler = exceptionHandler;
    }
    else {
        // 使用默认异常处理器SimpleAsyncUncaughtExceptionHandler
        this.exceptionHandler = new SimpleAsyncUncaughtExceptionHandler();
    }
    // 根据异步执行器和异常处理器生成Advice
    this.advice = buildAdvice(executor, this.exceptionHandler);
    // 生成Pointcut
    this.pointcut = buildPointcut(asyncAnnotationTypes);
}

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);
    // 重新生成Pointcut
    this.pointcut = buildPointcut(asyncAnnotationTypes);
}

protected Advice buildAdvice(@Nullable Executor executor, AsyncUncaughtExceptionHandler exceptionHandler) {
    // 使用AnnotationAsyncExecutionInterceptor
    return new AnnotationAsyncExecutionInterceptor(executor, exceptionHandler);
}

protected Pointcut buildPointcut(Set<Class<? extends Annotation>> asyncAnnotationTypes) {
    ComposablePointcut result = null;
    // 遍历注解类型集合,得到一个ComposablePointcut
    for (Class<? extends Annotation> asyncAnnotationType : asyncAnnotationTypes) {
        // 匹配类,忽略方法(MethodMatcher.TRUE)
        Pointcut cpc = new AnnotationMatchingPointcut(asyncAnnotationType, true);
        // 匹配方法,忽略类(ClassFilter.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);
}

至此可知,AsyncAnnotationBeanPostProcessor通过组合AnnotationMatchingPointcutComposablePointcut判断是否可以将AsyncAnnotationAdvisor切入到Bean中,然后通过AnnotationAsyncExecutionInterceptor进行增强处理;

AnnotationAsyncExecutionInterceptor

AnnotationAsyncExecutionInterceptor继承自AsyncExecutionAspectSupport,且实现了MethodInterceptor
AsyncExecutionAspectSupport实现了异步执行器的处理,代码如下:

protected AsyncTaskExecutor determineAsyncExecutor(Method method) {
    // 从缓存的信息中找到该Method对应的异步执行器
    AsyncTaskExecutor executor = this.executors.get(method);
    if (executor == null) {
        // 若未缓存,则需要解析对应的执行器
        Executor targetExecutor;
        // 获取执行器的合格者描述,若存在的话
        // 即@Async注解的value属性值
        String qualifier = getExecutorQualifier(method);
        if (StringUtils.hasLength(qualifier)) {
            // 若存在,则根据qualifier查找执行器
            targetExecutor = findQualifiedExecutor(this.beanFactory, qualifier);
        }
        else {
            // 不存在,则使用自定义的执行器
            targetExecutor = this.defaultExecutor;
            if (targetExecutor == null) {
                synchronized (this.executors) {
                    if (this.defaultExecutor == null) {
                        // 无自定义的执行器,则获取默认的执行器
                        this.defaultExecutor = getDefaultExecutor(this.beanFactory);
                    }
                    targetExecutor = this.defaultExecutor;
                }
            }
        }
        if (targetExecutor == null) {
            // 若还找不到执行器,则直接返回null
            return null;
        }
        // 包装targetExecutor为异步执行器
        executor = (targetExecutor instanceof AsyncListenableTaskExecutor ?
            (AsyncListenableTaskExecutor) targetExecutor : new TaskExecutorAdapter(targetExecutor));
        // 缓存该Method的异步执行器信息,方便下次直接从缓存中获取
        this.executors.put(method, executor);
    }
    return executor;
}

protected Executor findQualifiedExecutor(@Nullable BeanFactory beanFactory, String qualifier) {
    if (beanFactory == null) {
        throw new IllegalStateException("BeanFactory must be set on " + getClass().getSimpleName() +
                " to access qualified executor '" + qualifier + "'");
    }
    // 从BeanFactory中根据指定名称qualifier查找Executor类型Bean
    return BeanFactoryAnnotationUtils.qualifiedBeanOfType(beanFactory, Executor.class, qualifier);
}

protected Executor getDefaultExecutor(@Nullable BeanFactory beanFactory) {
    if (beanFactory != null) {
        try {
            // 先从BeanFactory中查找唯一的TaskExecutor类型Bean
            // Search for TaskExecutor bean... not plain Executor since that would
            // match with ScheduledExecutorService as well, which is unusable for
            // our purposes here. TaskExecutor is more clearly designed for it.
            return beanFactory.getBean(TaskExecutor.class);
        }
        catch (NoUniqueBeanDefinitionException ex) {
            logger.debug("Could not find unique TaskExecutor bean", ex);
            try {
                // 若存在多个,则继续根据名称"taskExecutor"查找Executor类型Bean
                return beanFactory.getBean(DEFAULT_TASK_EXECUTOR_BEAN_NAME, Executor.class);
            }
            catch (NoSuchBeanDefinitionException ex2) {
                if (logger.isInfoEnabled()) {
                    logger.info("More than one TaskExecutor bean found within the context, and none is named " +
                            "'taskExecutor'. Mark one of them as primary or name it 'taskExecutor' (possibly " +
                            "as an alias) in order to use it for async processing: " + ex.getBeanNamesFound());
                }
            }
        }
        catch (NoSuchBeanDefinitionException ex) {
            logger.debug("Could not find default TaskExecutor bean", ex);
            try {
                // 若找不到TaskExecutor类型Bean,则继续根据名称"taskExecutor"查找Executor类型Bean
                return beanFactory.getBean(DEFAULT_TASK_EXECUTOR_BEAN_NAME, Executor.class);
            }
            catch (NoSuchBeanDefinitionException ex2) {
                logger.info("No task executor bean found for async processing: " +
                        "no bean of type TaskExecutor and no bean named 'taskExecutor' either");
            }
            // Giving up -> either using local default executor or none at all...
        }
    }
    return null;
}

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;
    }
}

protected void handleError(Throwable ex, Method method, Object... params) throws Exception {
    if (Future.class.isAssignableFrom(method.getReturnType())) {
        // 如果Method返回值为Future,则rethrow异常
        ReflectionUtils.rethrowException(ex);
    }
    else {
        // Could not transmit the exception to the caller with default executor
        try {
            // 使用异常处理器处理异常
            this.exceptionHandler.handleUncaughtException(ex, method, params);
        }
        catch (Throwable ex2) {
            logger.error("Exception handler for async method '" + method.toGenericString() +
                    "' threw unexpected exception itself", ex2);
        }
    }
}

AsyncExecutionInterceptor重写了getDefaultExecutor方法,确保默认执行器存在;且实现MethodInterceptor的invoke方法,代码如下:

protected Executor getDefaultExecutor(@Nullable BeanFactory beanFactory) {
    Executor defaultExecutor = super.getDefaultExecutor(beanFactory);
    // 当找不到默认执行器,则使用SimpleAsyncTaskExecutor
    return (defaultExecutor != null ? defaultExecutor : new SimpleAsyncTaskExecutor());
}

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<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());
}

AsyncAnnotationBeanPostProcessor实现了getExecutorQualifier,从而支持@Async注解,代码如下:

protected String getExecutorQualifier(Method method) {
    // Maintainer's note: changes made here should also be made in
    // AnnotationAsyncExecutionAspect#getExecutorQualifier
    // 获取Method上的Async注解
    Async async = AnnotatedElementUtils.findMergedAnnotation(method, Async.class);
    if (async == null) {
        // 获取Method所在类上的Async注解
        async = AnnotatedElementUtils.findMergedAnnotation(method.getDeclaringClass(), Async.class);
    }
    // 使用Async注解的value属性值,若存在的话
    return (async != null ? async.value() : null);
}

常见问题

@Async注解失效

原因
一般是调用同一个类中的@Async注解标注的方法,此时无法经过AOP处理,导致异步执行失效;

解决方法
在调用方法中,从Bean容器中获取本类的代理实例,使用代理实例调用@Asyc注解标注的方法;

@Autowired
private ApplicationContext applicationContext;

public void invoke() {
    System.out.println("当前线程:" + Thread.currentThread().getName());
    Demo demo = applicationContext.getBean(Demo.class);
    demo.async();
}

@Async
public void async() {
    // do something
    System.out.println("当前线程:" + Thread.currentThread().getName());
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值