关于spring:Spring-Framework-异步任务原理

Spring Framework 异步工作原理

原因

Spring Framework 外部提供了除IOC和AOP之外的很多有意思的性能,深入研究其技术原理,可在我的项目技术选型上提供更多的思路,和技术把控。Spring Framewrok 代码由大佬精心打磨,能够从性能实现上学习和模拟。另外Spring Framework是Java我的项目开发的根底,其余技术框架都会基于或者与Spring 兼容,钻研其中的技术原理,可疾速把握其余技术框架的技术原理,比方 Spring boot \ Spring cloud…

简述

Spring Framework 提供了代码异步执行的性能。在须要异步执行的办法下面增加 @Async 注解,两外在@Configuration 类上减少 @EnableAsync 注解。代码执行到须要异步执行的办法上,就能够跨线程运行,达到异步执行的目标。

前提

Spring Framework 的异步工作性能是基于Spring AOP实现,Spring Aop 又是切面编程的一种,
须要对切面编程和 Spring Aop 中的根底概念有所理解。

注释

@EnableAsync

通过浏览注解的源文件 org.springframework.scheduling.annotation.EnableAsync 中正文,可对异步工作性能应用与定制有一个根本理解。

  1. 搭配@Configuration 注解一起应用。
  2. 反对 Spring’s @Async、 EJB 3.1 @jakarta.ejb.Asynchronous、 自定义注解(在 annotation() 中指定) 三种注解。
  3. 默认应用 org.springframework.core.task.SimpleAsyncTaskExecutor 线程池执行异步工作。能够通过自定义一个org.springframework.core.task.TaskExecutor Bean 或者 java.util.concurrent.Executor Bean 名字是 ‘taskExecutor’。
  4. 异步办法的执行产生的异样不能传递给调用方,对于为解决的异样仅打印日志。
  5. 通过实现 AsyncConfigurer 能够线程池和异样处理器进行定制。

    @Configuration
    @EnableAsync
    public class AppConfig implements AsyncConfigurer {
      
        // @Bean 不增加此注解也能失常应用,增加后该线程池能够被Spring 治理。
        @Override
        public Executor getAsyncExecutor() {
            ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
            executor.setCorePoolSize(7);
            executor.setMaxPoolSize(42);
            executor.setQueueCapacity(11);
            executor.setThreadNamePrefix("MyExecutor-");
            // 应用@Bean 后,能够正文上面一行,线程池的初始化工作会有Spring负责。
            executor.initialize();
            return executor;
        }
      
        @Override
        public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
            return new MyAsyncUncaughtExceptionHandler();
        }
    }
  6. mode 属性管制 advice 如何利用。默认是 AdviceMode.PROXY,其余属性能够管制代理的行为,代理后的办法只能通过代理援用调用,调用本类中的代理办法不会失效。
  7. 另外能够将 mode 属性 设置为 AdviceMode.ASPECTJ. 须要引入spring-aspectj jar,反对以后类办法调用。

将正文删除后的代码:

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

    Class<? extends Annotation> annotation() default Annotation.class;

    boolean proxyTargetClass() default false;

    AdviceMode mode() default AdviceMode.PROXY;

    int order() default Ordered.LOWEST_PRECEDENCE;

}

@EnableAsync 通过 @Import 引入 AsyncConfigurationSelector.

AsyncConfigurationSelector

依据@EnableAsync.mode返回 AbstractAsyncConfiguration 实现 ProxyAsyncConfiguration 或者 AspectJAsyncConfiguration

ProxyAsyncConfiguration

  1. 继承一个抽象类 AbstractAsyncConfiguration
  2. 创立 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;

AbstractAsyncConfiguration

  1. 实现接口 ImportAware, 在setImportMetadata 中对 enableAsync属性进行赋值。
  2. 主动注入 AsyncConfigurer,Only one AsyncConfigurer may exist, 将Bean中的线程池和失败处理器赋值到属性中。

以上类属于性能配置阶段, 从此开始进入异步工作性能执行相干类。

Spring Framework 异步工作的技术原理实质就是通过aop机制,对Bean进行代理,将办法的执行放入线程池中执行。
Spring Framework 中对Bean创立代理的做法就是实现 BeanPostProcessor接口,在Bean创立的过程中,对Bean的类注解或者办法注解进行规定匹配,匹配通过后会生成代理对象,对Bean进行加强。

AsyncAnnotationBeanPostProcessor

异步工作的后置处理器。

在Bean实例化过程中会调用所有的beanPostProcessor,这些BeanPostProcessor 能够在定义类的时候实现 BeanPostProcessor 接口并注册为Bean,在Spring容器启动过程中,会通过注解解析取得bean definition,在AbstractApplicationContext 的 refresh() 中,调用完 invokeBeanFactoryPostProcessors()后,将BeanFactory中所有BeanPostProcessor 实现类的Bean 收集到AbstractBeanFactory中的 beanPostProcessors书信中,在进行Bean创立时,调用初始化的前置或者后置beanPostProcessor时,会执行所有的BeanPostProcessor的实现类。

UML:

仅实现 BeanFactoryAware.setBeanFactory(), 创立 AsyncAnnotationAdvisor

        AsyncAnnotationAdvisor advisor = new AsyncAnnotationAdvisor(this.executor, this.exceptionHandler);
        if (this.asyncAnnotationType != null) {
            advisor.setAsyncAnnotationType(this.asyncAnnotationType);
        }
        advisor.setBeanFactory(beanFactory);
        this.advisor = advisor;

AsyncAnnotationAdvisor中蕴含 advice 和 pointcut,advice就是动静代理中加强逻辑对象,pointcut就是代理的切入点。并会在构造方法中对advice和pointcut进行创立。

    protected Advice buildAdvice(@Nullable Supplier<Executor> executor, @Nullable Supplier<AsyncUncaughtExceptionHandler> exceptionHandler) {
        AnnotationAsyncExecutionInterceptor interceptor = new AnnotationAsyncExecutionInterceptor(null);
        interceptor.configure(executor, exceptionHandler);
        return interceptor;
    }

AnnotationAsyncExecutionInterceptor 对象中蕴含异步工作执行逻辑代码。

    protected Pointcut buildPointcut(Set<Class<? extends Annotation>> asyncAnnotationTypes) {
        ComposablePointcut result = null;
        for (Class<? extends Annotation> asyncAnnotationType : asyncAnnotationTypes) {
            // 创立类  级别的匹配 MethodMatcher.TRUE
            Pointcut cpc = new AnnotationMatchingPointcut(asyncAnnotationType, true);
            // 创立办法级别的匹配 AnnotationMethodMatcher 
            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);
    }

创立基于指定注解的Pointcut,在结构器中会基于framework实现的两种注解 Async \ @jakarta.ejb.Asynchronous,另提供 setAsyncAnnotation 办法对自定义的异步注解进行从新设置,设置为仅反对指定注解的Pointcut。

在下面UML中能够看出 AsyncAnnotationBeanPostProcessor 继承了 AbstractAdvisingBeanPostProcessor, Async的后置解决逻辑也在此类中。

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

        if (bean instanceof Advised advised) {
            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;
            }
        }

        // 1.规定匹配
        if (isEligible(bean, beanName)) {
            ProxyFactory proxyFactory = prepareProxyFactory(bean, beanName);
            if (!proxyFactory.isProxyTargetClass()) {
                evaluateProxyInterfaces(bean.getClass(), proxyFactory);
            }
            proxyFactory.addAdvisor(this.advisor);
            customizeProxyFactory(proxyFactory);

            // Use original ClassLoader if bean class not locally loaded in overriding class loader
            ClassLoader classLoader = getProxyClassLoader();
            if (classLoader instanceof SmartClassLoader && classLoader != bean.getClass().getClassLoader()) {
                classLoader = ((SmartClassLoader) classLoader).getOriginalClassLoader();
            }
            // 2.创立代理
            return proxyFactory.getProxy(classLoader);
        }

        // No proxy needed.
        return bean;
    }

规定匹配

  1. 首先会对匹配后果进行缓存到eligibleBeans。
  2. 匹配逻辑是在 AopUtils.canApply(),具体代码在 org.springframework.aop.support.AopUtils#canApply(org.springframework.aop.Pointcut, java.lang.Class<?>, boolean) 中,能够对照代码进行剖析。
  3. Pointcut构建的时候能够指定classFilter,匹配过程中会进行排除。
  4. pointcut的办法匹配器 MethodMatcher,若是类级别的匹配,会间接返回匹配胜利的后果。
  5. 指标类的Class对象,以及所有接口的Class对象进行收集。
  6. 遍历Class对象,获取Class对象的所有办法进行遍历,应用 AnnotationMethodMatcher 对办法注解进行匹配。

生成代理

  1. 指标类的所有接口都会设置到 ProxyFactory中。
  2. 设置以后Advisor到ProxyFactory中。
  3. ProxyFactory 创立代理。

结尾

以上就是对Spring Framework 异步工作的根本介绍,其中AnnotationAsyncExecutionInterceptor相干代码没有进行具体阐明。异步工作的根本技术原理进行了梳理,后续会对其余性能持续梳理。

【腾讯云】轻量 2核2G4M,首年65元

阿里云限时活动-云数据库 RDS MySQL  1核2G配置 1.88/月 速抢

本文由乐趣区整理发布,转载请注明出处,谢谢。

您可能还喜欢...

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据