学习注解,从注释和源码入手
部分关键注释,我自己标注了一些中文注释便于理解:
/** * Enables Spring's asynchronous method execution capability, similar to functionality * found in Spring's {@code <task:*>} XML namespace. * <p> * -- 与@Configuration注解配合使用,在Spring应用程序上下文中实现注解驱动的异步处理功能 * <p>To be used together with @{@link Configuration Configuration} classes as follows, * enabling annotation-driven async processing for an entire Spring application context: * <p>
* <pre class="code"> * @Configuration * @EnableAsync * public class AppConfig {<!-- --> * * }</pre> * <p>
* {<!-- -->@code MyAsyncBean} is a user-defined type with one or more methods annotated with * either Spring's {<!-- -->@code @Async} annotation, the EJB 3.1 {<!-- -->@code @javax.ejb.Asynchronous} * annotation, or any custom annotation specified via the {<!-- -->@link #annotation} attribute. * The aspect is added transparently for any registered bean, for instance via this * configuration: * * <pre class="code"> * @Configuration * public class AnotherAppConfig {<!-- --> * * @;Bean * public MyAsyncBean asyncBean() {<!-- --> * return new MyAsyncBean(); * } * }</pre> * <p>
* <p>By default, Spring will be searching for an associated thread pool definition: * either a unique {<!-- -->@link org.springframework.core.task.TaskExecutor} bean in the context, * or an {<!-- -->@link java.util.concurrent.Executor} bean named "taskExecutor" otherwise. If * neither of the two is resolvable, a {<!-- -->@link org.springframework.core.task.SimpleAsyncTaskExecutor} * will be used to process async method invocations. Besides, annotated methods having a * {<!-- -->@code void} return type cannot transmit any exception back to the caller. By default, * such uncaught exceptions are only logged. * <p>
* <p>To customize all this, implement {<!-- -->@link AsyncConfigurer} and provide: * <ul> * <li>your own {<!-- -->@link java.util.concurrent.Executor Executor} through the * {<!-- -->@link AsyncConfigurer#getAsyncExecutor getAsyncExecutor()} method, and</li> * <li>your own {<!-- -->@link org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler * AsyncUncaughtExceptionHandler} through the {<!-- -->@link AsyncConfigurer#getAsyncUncaughtExceptionHandler * getAsyncUncaughtExceptionHandler()} * method.</li> * </ul>
* <p><b>NOTE: {<!-- -->@link AsyncConfigurer} configuration classes get initialized early * in the application context bootstrap. If you need any dependencies on other beans * there, make sure to declare them 'lazy' as far as possible in order to let them * go through other post-processors as well.</b> * <p>
* <pre class="code"> * @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(); * } * }</pre> */
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Import(AsyncConfigurationSelector.class) public @interface EnableAsync {<!-- -->
/** * Indicate the 'async' annotation type to be detected at either class * or method level. * <p>By default, both Spring's @{@link Async} annotation and the EJB 3.1 * {@code @javax.ejb.Asynchronous} annotation will be detected. * <p>This attribute exists so that developers can provide their own * custom annotation type to indicate that a method (or all methods of * a given class) should be invoked asynchronously. */ Class<? extends Annotation> annotation() default Annotation.class;
/** * Indicate whether subclass-based (CGLIB) proxies are to be created as opposed * to standard Java interface-based proxies. * <p><strong>Applicable only if the {@link #mode} is set to {@link AdviceMode#PROXY}</strong>. * <p>The default is {@code false}. * <p>Note that setting this attribute to {@code true} will affect <em>all</em> * Spring-managed beans requiring proxying, not just those marked with {@code @Async}. * For example, other beans marked with Spring's {@code @Transactional} annotation * will be upgraded to subclass proxying at the same time. This approach has no * negative impact in practice unless one is explicitly expecting one type of proxy * vs. another — for example, in tests. */ boolean proxyTargetClass() default false;
/** * Indicate how async advice should be applied. * <p><b>The default is {@link AdviceMode#PROXY}.</b> * Please note that proxy mode allows for interception of calls through the proxy * only. Local calls within the same class cannot get intercepted that way; an * {@link Async} annotation on such a method within a local call will be ignored * since Spring's interceptor does not even kick in for such a runtime scenario. * For a more advanced mode of interception, consider switching this to * {@link AdviceMode#ASPECTJ}. */ AdviceMode mode() default AdviceMode.PROXY;
/** * Indicate the order in which the {@link AsyncAnnotationBeanPostProcessor} * should be applied. * <p>The default is {@link Ordered#LOWEST_PRECEDENCE} in order to run * after all other post-processors, so that it can add an advisor to * existing proxies rather than double-proxy. */ int order() default Ordered.LOWEST_PRECEDENCE;
点进@EnableAsync的@Import(AsyncConfigurationSelector.class)
AsyncConfigurationSelector中,selectImports方法在spring容器扫描bean的时候,根据通知模型判断要导入哪一个类
/** * Returns {@link ProxyAsyncConfiguration} or {@code AspectJAsyncConfiguration} * for {@code PROXY} and {@code ASPECTJ} values of {@link EnableAsync#mode()}, * respectively. */ @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; } }
默认是proxy
返回的类为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 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; } }
这个类是一个配置类,实现了BeanPostProcessor接口,它向spring容器中添加了一个AsyncAnnotationBeanPostProcessor的bean后置处理器,其父类AbstractAdvisingBeanPostProcessor中定义了处理器
@Override public Object postProcessBeforeInitialization(Object bean, String beanName) {<!-- --> return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) {<!-- --> if (this.advisor == null || bean instanceof AopInfrastructureBean) {<!-- --> // Ignore AOP infrastructure such as scoped proxies. return bean; } // 类中加@Async的bean会走到这个if里,添加advisor 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; } } if (isEligible(bean, beanName)) {<!-- --> 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; }
可以看出前置处理器未做处理,后置处理器对添加了@Async的bean进行了addAdvisor,后续使用bean时,debug看一下,该bean中会有响应的advisor
@EnableAsync通过向Spring引入后置处理器AsyncAnnotationBeanPostProcessor,在bean的创建过程中对bean进行advisor增强,对@Async标识的bean增强异步功能