当前位置: 首页 > 后端技术 > Java

SpringFramework异步任务原理

时间:2023-04-01 23:39:38 Java

SpringFramework异步任务原理SpringFramework之所以在内部除了IOC和AOP之外还提供了很多有趣的功能,深入研究其技术原理可以在项目技术选型、技术把控上提供更多思路.SpringFramewrok的代码经过高手们的精心打磨,从功能的实现上可以学习和模仿。另外,SpringFramework是Java项目开发的基础。其他技术框架将基于或兼容Spring。通过学习技术原理,可以快速掌握其他技术框架的技术原理,比如Springboot\Springcloud...简介SpringFramework提供了异步执行代码的功能。在需要异步执行的方法上加上@Async注解,在@Configuration类上加上@EnableAsync注解。当代码执行到需要异步执行的方法时,可以跨线程运行,达到异步执行的目的。前提SpringFramework的异步任务功能是基于SpringAOP实现的,SpringAop是一种切面编程。需要了解切面编程和SpringAop的基本概念。文@EnableAsync通过浏览源文件org.springframework.scheduling.annotation.EnableAsync中的注解,可以对异步任务功能的使用和自定义有一个基本的了解。与@Configuration注解一起使用。支持Spring的@Async、EJB3.1@jakarta.ejb.Asynchronous和自定义注解(在annotation()中指定)。默认情况下,org.springframework.core.task.SimpleAsyncTaskExecutor线程池用于执行异步任务。你可以自定义一个org.springframework.core.task.TaskExecutorBean或者java.util.concurrent.ExecutorBeanname是'taskExecutor'。异步方法执行产生的异常不能传递给调用者,对于未处理的异常只会打印日志。可以通过实现AsyncConfigurer来自定义线程池和异常处理程序。@Configuration@EnableAsyncpublicclassAppConfigimplementsAsyncConfigurer{//@Bean不加这个注解也可以正常使用。添加后,线程池就可以由Spring来管理了。@OverridepublicExecutorgetAsyncExecutor(){ThreadPoolTask??Executorexecutor=newThreadPoolTask??Executor();executor.setCorePoolSize(7);executor.setMaxPoolSize(42);executor.setQueueCapacity(11);executor.setThreadNamePrefix("MyExecutor-");@Bean之后可以注释下面一行,Spring会负责线程池的初始化。executor.initialize();回归执行人;}@OverridepublicAsyncUncaughtExceptionHandlergetAsyncUncaughtExceptionHandler(){返回新的MyAsyncUncaughtExceptionHandler();}}mode属性控制建议的应用方式。默认是AdviceMode.PROXY,其他属性可以控制代理的行为。代理后面的方法只能通过代理引用调用,调用本类中的代理方法不会生效。此外,您可以将模式属性设置为AdviceMode.ASPECTJ。需要引入spring-aspectjjar来支持当前类的方法调用。删除注解后的代码:@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Import(AsyncConfigurationSelector.class)public@interfaceEnableAsync{Class注解()默认注解类;布尔proxyTargetClass()默认false;AdviceModemode()defaultAdviceMode.PROXY;intorder()defaultOrdered.LOWEST_PRECEDENCE;}@EnableAsync引入AsyncConfigurationSelector通过@Import.AsyncConfigurationSelector返回AbstractAsyncConfigAsyncConfiguration或根据@EnableAsync.mode实现JProxyAsync。ProxyAsyncConfiguration继承了一个抽象类AbstractAsyncConfiguration。创建AsyncAnnotationBeanPostProcessor,将默认或自定义的线程池和失败处理程序放入其中。AsyncAnnotationBeanPostProcessorbpp=newAsyncAnnotationBeanPostProcessor();bpp.configure(this.executor,this.exceptionHandler);ClasscustomAsyncAnnotation=this.enableAsync.getClass("annotation");if(customAsyncAnnotation!=AnnotationUValtils.getDefaultAsync(.class,"annotation")){bpp.setAsyncAnnotationType(customAsyncAnnotation);}bpp.setProxyTargetClass(this.enableAsync.getBoolean("proxyTargetClass"));bpp.setOrder(this.enableAsync.getNumber("order"));returnbpp;AbstractAsyncConfiguration实现接口ImportAware,并为setImportMetadata中的enableAsync属性赋值。自动注入AsyncConfigurer,只能有一个AsyncConfigurer,将Bean中的线程池和failurehandler赋给属性。以上类属于功能配置阶段,之后进入异步任务功能执行的相关类。SpringFramework异步任务的技术原理本质是通过aop机制代理Bean,将方法的执行放到线程池中执行。SpringFramework中为Bean创建代理的方式是实现BeanPostProcessor接口。在创建Bean的过程中,对Bean的类注解或方法注解进行规则匹配。匹配通过后,会生成一个代理对象来增强Bean。AsyncAnnotationBeanPostProcessor用于异步任务的后处理器。所有的beanPostProcessor都会在Bean实例化过程中被调用。这些BeanPostProcessor可以实现BeanPostProcessor接口,在定义类的时候注册为bean。在Spring容器启动过程中,会通过注解解析获取bean定义。在AbstractApplicationContext的refresh()中,调用invokeBeanFactoryPostProcessors()后,将BeanFactory中所有BeanPostProcessor实现类的bean收集到AbstractBeanFactory中的beanPostProcessors字母中。当创建一个Bean时,当调用初始化的pre-或post-beanPostProcessor时,所有BeanPostProcessor实现都会被执行。UML:仅实现BeanFactoryAware.setBeanFactory(),创建AsyncAnnotationAdvisorAsyncAnnotationAdvisoradvisor=newAsyncAnnotationAdvisor(this.executor,this.exceptionHandler);如果(this.asyncAnnotationType!=null){advisor.setAsyncAnnotationType(this.asyncFnnotationType).set}Beanadvise(beanFactory);this.advisor=顾问;AsyncAnnotationAdvisor包含advice和pointcut,advice是动态代理中的增强逻辑对象,pointcut是代理的入口点。通知和切入点将在构造方法中创建。protectedAdvicebuildAdvice(@NullableSupplierexecutor,@NullableSupplierexceptionHandler){AnnotationAsyncExecutionInterceptor拦截器=newAnnotationAsyncExecutionInterceptor(null);拦截器配置(执行器,异常处理程序);返回拦截器;}AnnotationAsyncExecutionInterceptor对象中包包含异步执行任务的逻辑代码。protectedPointcutbuildPointcut(Set>asyncAnnotationTypes){ComposablePointcutresult=null;for(ClassasyncAnnotationType:asyncAnnotationTypes){//创建类级匹配MethodMatcher.TRUEPointcutcpc=newAnnotationMatchingPointcut(asyncAnnotationType,true);//创建方法级匹配AnnotationMethodMatcherPointcutmpc=newAnnotationMatchingPointcut(null,asyncAnnotationType,true);if(result==null){result=newComposablePointcut(cpc);}else{result.union(cpc);}result=result.union(mpc);}return(result!=null?result:Pointcut.TRUE);}根据指定的注解创建切入点。在构造函数中,会基于框架Async\@jakarta.ejb.Asynchronous实现的两个注解,也提供了setAsyncAnnotation方法来重置自定义异步注解,设置为只支持指定注解的Pointcut。从上面的UML可以看出,AsyncAnnotationBeanPostProcessor继承了AbstractAdvisingBeanPostProcessor,Async的后处理逻辑也在这个类中。@OverridepublicObjectpostProcessAfterInitialization(Objectbean,StringbeanName){if(this.advisor==null||beaninstanceofAopInfrastructureBean){//忽略范围代理等AOP基础设施。返回豆;}if(beaninstanceofAdvisedadvised){if(!advised.isFrozen()&&isEligible(AopUtils.getTargetClass(bean))){//将我们的本地Advisor添加到现有代理的Advisor链中...if(this.beforeExistingAdvisors){advised.addAdvisor(0,this.advisor);}else{advised.addAdvisor(this.advisor);}返回豆;}}//1.规则匹配if(isEligible(bean,beanName)){ProxyFactoryproxyFactory=prepareProxyFactory(bean,beanName);if(!proxyFactory.isProxyTargetClass()){evaluateProxyInterfaces(bean.getClass(),proxyFactory);}proxyFactory.addAdvisor(this.advisor);定制代理工厂(代理工厂);//如果bean类没有在覆盖类加载器中本地加载,则使用原始ClassLoaderClassLoaderclassLoader=getProxyClassLoader();if(classLoaderinstanceofSmartClassLoader&&classLoader!=bean.getClass().getClassLoader()){classLoader=((SmartClassLoader)classLoader).getOriginalClassLoader();}//2.创建代理returnproxyFactory.getProxy(classLoader);}//不需要代理。返回豆;}规则匹配会先将匹配结果缓存到eligibleBeans中,匹配逻辑在AopUtils.canApply()中,具体代码在org.springframework.aop.support.AopUtils#canApply(org.springframework.aop.Pointcut,java.lang.Class,boolean)可以针对代码进行分析。ClassFilter可以在构建Pointcut时指定,在匹配过程中会被排除。Pointcut的方法匹配器MethodMatcher,如果是类级别的匹配,会直接返回匹配成功的结果。收集目标类的Class对象和所有接口的Class对象。遍历Class对象,获取Class对象的所有方法进行遍历,使用AnnotationMethodMatcher匹配方法注解。生成的代理目标类的所有接口都将设置到ProxyFactory中。将当前Advisor设置为ProxyFactory。ProxyFactory创建代理。最后,以上是对SpringFramework异步任务的基本介绍,AnnotationAsyncExecutionInterceptor相关代码不再赘述。异步任务的基本技术原理整理完毕,其他功能后续会继续整理。