@Async源码分析
2022-01-12 17:41:44 54 举报
AI智能生成
登录查看完整内容
@Async源码分析
作者其他创作
大纲/内容
1. 开启@EnableAsync注解会@Import(AsyncConfigurationSelector.class) 主要是重写selectImports方法读取EnableAsync中配置的mode值来加载不同的代理方式 默认是PROXY 采用Spring的动态代理(含JDK动态代理和CGLIB)
1. 父类AbstractAsyncConfiguration通过@Autowired注入容器中的AsyncConfigurer配置到setConfigurers方法 这样用户可以自定义executor和exceptionHandler,需要注意的是只支持一个AsyncConfigurer配置,如果容器中存在多个会抛出异常
2. 父类AbstractAsyncConfiguration实现了ImportAware方法,所以会先执行setImportMetadata方法 将EnableAsync注解中的属性配置读到this.enableAsync中供子类使用
1. 实例化一个AsyncAnnotationBeanPostProcessor对象,注意构造方法中会设置beforeExistingAdvisors=true AsyncAnnotationBeanPostProcessor bpp = new AsyncAnnotationBeanPostProcessor();
2. 为后置处理器设置线程执行器和异常处理 font color=\"#0076b3\
3. 获取EnableAsync是否有设置annotation的值,该值为一个注解,用来标识有该注解的类或方法是需要代理的 没设置的话默认是@Async注解
4. 获取EnableAsync的proxyTargetClass值设置代理模式,默认是false,表示是jdk代理 bpp.setProxyTargetClass(this.enableAsync.getBoolean(\"proxyTargetClass\"));
5. 获取EnableAsync的order属性值,决定的是BeanProcessor的执行顺序的 bpp.setOrder(this.enableAsync.<Integer>getNumber(\"order\"));
3. 加载本类定义的AsyncAnnotationBeanPostProcessor 后置处理器bean
2. 上一步selectImports会返回ProxyAsyncConfiguration类的全限定名 最终按照执行顺序会执行右侧操作
1. 调用父类的setBeanFactory方法 super.setBeanFactory(beanFactory);
1. 定义一个Set存储默认的代理的注解标识,供后面buildPointcut使用 Set<Class<? extends Annotation>> asyncAnnotationTypes = new LinkedHashSet<>(2);
2. 将默认的Async标识添加到上面的asyncAnnotationTypes 中 asyncAnnotationTypes.add(Async.class);
3. 如果存在javax.ejb.Asynchronous类则也添加到asyncAnnotationTypes 中,一般不会存在
1. 实例化一个AnnotationAsyncExecutionInterceptor对象,该类实现了MethodInterceptor接口 调用代理目标类方法时就是执行此方法逻辑 AnnotationAsyncExecutionInterceptor interceptor = new AnnotationAsyncExecutionInterceptor(null);
2. 将前面传入的executor和exceptionHander分别加上各自的默认值构造成SingletonSupplier 赋值给defaultExecutor 和exceptionHandler font color=\"#0076b3\
3. 返回interceptor对象 return interceptor;
4. 构建通知font color=\"#0076b3\
5. 通过传入的asyncAnnotationTypes集合中的注解构造切点,构造出的切点只有被注解标识的类或方法才会被切入 this.pointcut = buildPointcut(asyncAnnotationTypes);
2. 实例化一个AsyncAnnotationAdvisor对象,该对象中包含通知(advice)和切入点(pointcut) font color=\"#0076b3\
3. 如果this.asyncAnnotationType值(#2.3.3中会去获取该值)不为null则添加并重写执行#3.2.5的buildPointcut操作 advisor.setAsyncAnnotationType(this.asyncAnnotationType);
4. 为advisor设置BeanFactory advisor.setBeanFactory(beanFactory);
5. 将advisor赋值给this.advisor供后面添加代理使用 this.advisor = advisor;
AsyncAnnotationBeanPostProcessor类关系图
3. 在初始化AsyncAnnotationBeanPostProcessor后置处理器的时候 由于它实现了BeanFactoryAware接口所以会执行setBeanFactory方法
1. 如果this.advisor(#3.5中有赋值)为null 或 当前处理的bean为AopInfrastructureBean类型则不进行代理,直接返回
jdk代理实现Advised接口可查看“spring ProxyFactory源码分析#4.2.1”
1. 将当前bean转为Advised类型,不管是通过gclib还是jdk代理都是会实现Advised接口的 Advised advised = (Advised) bean;
2. advised未被冻结且符合且当前bean符合切入条件则将this.advisor添加到advised中进行返回 添加的优先顺序可通过this.beforeExistingAdvisors控制(#2.3.1中构造函数里面默认设置该值为true)
2. 如果这个bean被代理过了
1. 用当前bean 创建一个ProxyFactory font color=\"#0076b3\
需要注意的是,如果发现代理对象没有实现接口或实现的接口里面没有方法则还是会使用cglib代理如果出现有实现接口,接口里面也有方法但不包括@Async标注的方法后面代理的时候是会报错的
2. 如果是使用的jdk代理,则分析出它所实现的接口,然后放入ProxyFactory font color=\"#0076b3\
3. 将this.advisor添加到代理工厂中 proxyFactory.addAdvisor(this.advisor);
4. 留给子类扩展的方法 customizeProxyFactory(proxyFactory);
5. 通过proxyFactory获取代理对象进行返回 return proxyFactory.getProxy(getProxyClassLoader());
3. 如果bean没有被代理过但符合切入条件
4. 如果上面的情况都不符合则说明不需要进行代理操作,直接返回bean就行了 return bean;
4. 在普通bean初始化的时候调用AsyncAnnotationBeanPostProcessor 后置处理器的postProcessAfterInitialization方法进行处理
1. 拿到最终要执行的方法
1. 先通过方法从缓存中看能不能取到值,能直接返回,不能则进行下面的查找操作
2. 定义一个Executor类型的变量 Executor targetExecutor;
3. 获取方法上@Async注解是否有设置value值,如果有则将该值作为qualifier去容器中查找Executor类型的beanfont color=\"#0076b3\
1. 优先从SingletonSupplier#singletonInstance中取值
2. 如果上一步没有取到则从SingletonSupplier#sinstanceSupplier中取值 如果有自定义AsyncConfigurer配置在#2.4.2中会设置给sinstanceSupplier,就会使用该线程执行器
1. 从bean容器中查找TaskExecutor类型的bean,如果刚好存在该类型唯一的一个bean则就使用这个执行器了 在TaskExecutionAutoConfiguration中会默认在容器中注册了一个懒加载的ThreadPoolTaskExecutor bean 所以一般没有指定的情况下默认就是使用这个执行器了 return beanFactory.getBean(TaskExecutor.class);
2. 上面从bean容器中通过TaskExecutor类型去bean容器中去取的时候发现有多个会抛出异常进入这里 那就通过名称和Executor去取 font color=\"#0076b3\
3. 在./1中没有取到抛出异常时进入到这一步,执行的操作其实和./2中一样
3. 如果上面都没有取到就取默认值了,默认值也是在#2.4.2有设置的为() -> getDefaultExecutor(this.beanFactory) instance = this.defaultSupplier.get();
4. 如果@Async没有设置value值则去 this.defaultExecutor中去找了,如果这一步都没找到就返回null了 targetExecutor = this.defaultExecutor.get();
5. 上面有获取到targetExecutor且该值为AsyncListenableTaskExecutor 类型则直接作为执行器 如果不是该类型则通过TaskExecutorAdapter适配成AsyncListenableTaskExecutor
6. 将执行器放入executes缓存中,下次进来在./1就直接取到返回了 font color=\"#0076b3\
2. 获取异步任务执行器 AsyncTaskExecutor executor = determineAsyncExecutor(userDeclaredMethod);
3. 定义一个Callable 任务,任务里面会执行目标方法的调用,如果目标方法为返回值为Future,会返回Future#get值,否则返回null Object result = invocation.proceed();
1. 返回值类型是CompletableFuture
2. 返回值类型是ListenableFuture
3. 返回值类型是Future
4. 不符合上述情况说明没有返回值则通过执行器执行任务后返回null
@Async带返回值的代码示例
4. 通过./2中获取的executor执行 ./3 中的task,最终返回一个Future对象(如使用默认的ThreadPoolTaskExecutor 返回的是FutureTask对象) font color=\"#0076b3\
5. 在调用@Async标注的目标方法时最终会调用AsyncExecutionInterceptor#invoke方法 该对象是在#2.4.1构建通知的时候实例化的
@Async源码分析
0 条评论
回复 删除
下一页