美文网首页
Spring 中的 @Aysnc 是如何实现的?【咱们一起读源码

Spring 中的 @Aysnc 是如何实现的?【咱们一起读源码

作者: uhfun | 来源:发表于2022-11-11 17:00 被阅读0次

该文章为原创(转载请注明出处):Spring 中的 @Aysnc 是如何实现的?【咱们一起读源码】 - 简书 (jianshu.com)

Spring 中的 @Aysnc 是如何实现的?【咱们一起读源码】 使用效果

使用@Aysnc 添加在Bean实例的类上或者方法上,方法执行会交由指定的 线程池或者默认线程池异步执行。

涉及的类

代码阅读基于
Sping-context-5.1.6-RELEASE
Spring-aop-5.1.6-RELEASE

// 注解类
org.springframework.scheduling.annotation.Async    (@Async注解)
org.springframework.scheduling.annotation.EnableAsync    (引入@Async配置类)

// 配置类
org.springframework.scheduling.annotation.AsyncConfigurationSelector    (引入配置)
org.springframework.scheduling.annotation.ProxyAsyncConfiguration    (注册BeanPostProcessor Bean实例,使@Async注解生效)

// Spring中的Bean增强
org.springframework.scheduling.annotation.AsyncAnnotationBeanPostProcessor    (指定自定义切面)
    org.springframework.aop.framework.autoproxy.AbstractBeanFactoryAwareAdvisingPostProcessor    
        org.springframework.aop.framework.AbstractAdvisingBeanPostProcessor    (针对Bean实例构建代理的抽象类)

// 切面相关类
org.springframework.scheduling.annotation.AsyncAnnotationAdvisor    (切面切点逻辑抽象)
org.springframework.scheduling.annotation.AnnotationAsyncExecutionInterceptor    (帮助寻找线程池bean实例)
    org.springframework.aop.interceptor.AsyncExecutionInterceptor    (异步执行拦截器,核心逻辑为反射调用)
        org.springframework.aop.interceptor.AsyncExecutionAspectSupport    (抽象了选择执行线程池的逻辑层)
            org.aopalliance.intercept.MethodInterceptor    (抽象出来的方法拦截接口)
                org.aopalliance.intercept.Interceptor    (抽象出来的拦截器接口)
                    org.aopalliance.aop.Advice    (切面中的通知概念的抽象接口)

org.springframework.aop.support.annotation.AnnotationMatchingPointcut    (根据注解指定的切点)
org.springframework.aop.support.ComposablePointcut    (复合模式中的切点,包装多种切点,对外暴露一种的复合结构,遵守原有的接口定义)
    org.springframework.aop.Pointcut    (切面中的切点概念的抽象接口)

// 代理类相关
org.springframework.aop.framework.ProxyFactory    (代理工厂)
    org.springframework.aop.framework.ProxyCreatorSupport    (代理创建功能的逻辑抽象)
        org.springframework.aop.framework.AdvisedSupport    (切面功能的逻辑抽象)

org.springframework.aop.framework.CglibAopProxy    (Cglib创建代理逻辑)
// 代理切面拦截
org.springframework.aop.framework.CglibAopProxy.DynamicAdvisedInterceptor    (CGlib中的拦截)
    org.springframework.cglib.proxy.MethodInterceptor    (CGLIB代理 方法拦截器)

org.springframework.aop.framework.CglibAopProxy.CglibMethodInvocation    (CGLIB代理切面执行的逻辑抽象)
    org.springframework.aop.framework.ReflectiveMethodInvocation    (代理切面执行的逻辑抽象)
        org.springframework.aop.ProxyMethodInvocation    (方法反射的切面执行抽象)
            org.aopalliance.intercept.MethodInvocation       (方法执行的抽象) 
                org.aopalliance.intercept.Invocation
                    org.aopalliance.intercept.Joinpoint   (切面中的连接点概念的抽象接口)    

涉及类的简单讲解

涉及的类大致分为
@Async本身功能使用过程中的类
• 配置生效过程的类
• 切面定义 相关的类
• 生成切面代理 相关的类
• 代理的反射调用 相关的类

源码流程讲解

配置类生效
所有的一切来自于一个小小的注解 @EnableAsync
// 使用EnableAsync注解,proxyTargetClass=true 交由CGLIB创建代理
// 注解上带有 @Import(AsyncConfigurationSelector.class)
org.springframework.scheduling.annotation.EnableAsync
// 方法会根据 ImportSelector的选择使用对应的配置类
org.springframework.scheduling.annotation.AsyncConfigurationSelector#selectImports
// 默认选择了    org.springframework.context.annotation.AdviceMode.PROXY 代理模式
// 选择进入了 ProxyAsyncConfiguration配置类
org.springframework.scheduling.annotation.ProxyAsyncConfiguration 
// 配置类只做了一件事,注册了一个BeanPostProcessor Bean实例
org.springframework.scheduling.annotation.ProxyAsyncConfiguration#asyncAdvisor

// 开始增强Bean
org.springframework.scheduling.annotation.AsyncAnnotationBeanPostProcessor
切面的准备工作
// 初始化AsyncAnnotationBeanPostProcessor Bean时
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#invokeAwareMethods
    // 指定了
    org.springframework.scheduling.annotation.AsyncAnnotationBeanPostProcessor#setBeanFactory
        // 构造了Advisor
        org.springframework.scheduling.annotation.AsyncAnnotationAdvisor
        // 保存了Advisor的引用,后续在创建代理的时候 会将这里的Advisor 传递使用!!
        org.springframework.aop.framework.AbstractAdvisingBeanPostProcessor#advisor
增强Bean,创建代理

对原有的Bean实例进行代理包装,这时只是保存了Advisor即切点和切面逻辑的抽象引用对象

// 如果已经为Aop代理对象(bean instanceof Advised),加入advisor
// 没有则创建代理实例
org.springframework.aop.framework.AbstractAdvisingBeanPostProcessor#postProcessAfterInitialization
    // 将之前准备好的切点切面 org.springframework.aop.Advisor引用保存到 ProxyFactory,再供后续使用!!
    org.springframework.aop.framework.AdvisedSupport#addAdvisor(org.springframework.aop.Advisor)
        // 记录Advisor
        org.springframework.aop.framework.AdvisedSupport#addAdvisor(int, org.springframework.aop.Advisor)
            // 记录到内部
            org.springframework.aop.framework.AdvisedSupport#addAdvisorInternal
                // Advisors 更新到 advisor数组 
                org.springframework.aop.framework.AdvisedSupport#updateAdvisorArray
                    org.springframework.aop.framework.AdvisedSupport#advisorArray
    // 开始获取代理实例
    org.springframework.aop.framework.ProxyFactory#getProxy(java.lang.ClassLoader)
        org.springframework.aop.framework.ProxyCreatorSupport#createAopProxy
            // 创建Aop代理抽象「AopProxy」,这时候传入的对象是 AdvisedSupport 就是ProxyFactory本身
            org.springframework.aop.framework.DefaultAopProxyFactory#createAopProxy
                // 这时候选择对应的AopProxy的实现,这里用到的是ObjenesisCglibAopProxy,也可能是其他实现
                org.springframework.aop.framework.ObjenesisCglibAopProxy#ObjenesisCglibAopProxy
                    // 走到父类的构造方法,将AdvisedSupport实例保存起来,这个变量比较关键
                    org.springframework.aop.framework.CglibAopProxy#CglibAopProxy
                
            // 拿到了AopProxy,开始创建真正的代理对象                       
            // 交由CGLIB AopProxy创建代理类实例
            org.springframework.aop.framework.CglibAopProxy#getProxy(java.lang.ClassLoader)
                // 搜集CallBack 这边的Aop CallBack
                // 使用的是org.springframework.aop.framework.CglibAopProxy.DynamicAdvisedInterceptor 
                // 基于 org.springframework.cglib.proxy.MethodInterceptor
                org.springframework.aop.framework.CglibAopProxy#getCallbacks
                    // 构造用于CGLIB 代理的Callback - 方法拦截器,这时候传入的对象是 AdvisedSupport 就是ProxyFactory本身
                    org.springframework.aop.framework.CglibAopProxy.DynamicAdvisedInterceptor
                // 配置完 org.springframework.cglib.proxy.Enhancer,创建正在的代理实例
                org.springframework.aop.framework.CglibAopProxy#createProxyClassAndInstance

// 至此Bean的代理创建完毕,关于切面还不是很清晰,因为到这里只是对原有bean进行增强,具体的增强还是在切面逻辑里
运行时执行,切面代理生效
// 调用方法,方法进入 代理拦截器
org.springframework.aop.framework.CglibAopProxy.DynamicAdvisedInterceptor#intercept
    // 获取切面逻辑
    org.springframework.aop.framework.AdvisedSupport#getInterceptorsAndDynamicInterceptionAdvice
        // 根据方法,类过滤保留的 方法拦截的切面逻辑
        org.springframework.aop.framework.DefaultAdvisorChainFactory#getInterceptorsAndDynamicInterceptionAdvice
            // 获取advisors,之前保留的advisorArray变量
            org.springframework.aop.framework.Advised#getAdvisors
            // 根据 class和method 条件过滤
            org.springframework.aop.support.annotation.AnnotationMatchingPointcut#getClassFilter
        // 缓存方法和对应的切面,后续再进入不需要再过滤查找是否执行切面逻辑
        org.springframework.aop.framework.AdvisedSupport#methodCache
    // 创建CglibMethodInvocation, 传入了 切面方法拦截器
    org.springframework.aop.framework.CglibAopProxy.CglibMethodInvocation
    // 执行方法反射
    org.springframework.aop.framework.ReflectiveMethodInvocation#proceed
        // 走到异步方法拦截的切面
        org.springframework.aop.interceptor.AsyncExecutionInterceptor#invoke
            // 找到注解对应的线程池
            org.springframework.aop.interceptor.AsyncExecutionAspectSupport#determineAsyncExecutor
            // 提交任务,交给线程池执行
            org.springframework.aop.interceptor.AsyncExecutionAspectSupport#doSubmit
// 至此方法交给线程池执行完成,方法返回如果是 Future 类型,方法会直接返回,否则异步执行,返回null,并不会阻塞等待完成

简单总结

• 通过@EnableAysnc注解开启该功能
• 基于Spring配置类的框架能力,注册了一个强化bean的BeanPostProcessororg.springframework.scheduling.annotation.AsyncAnnotationBeanPostProcessor
AsyncAnnotationBeanPostProcessor 设置了一个Advisor用于代理的切面方法拦截
AsyncAnnotationBeanPostProcessor 在bean初始化之后对原有对象实例封装了一层代理或者是在原有代理基础上增加了方法拦截
• 方法真实调用时,反射进入代理拦截,再根据切点判断是否执行切面
• 进入切面逻辑后,根据注解标注的线程池bean名称,选择对应的线程池bean实例,并交给该线程池执行

该文章为原创(转载请注明出处):Spring 中的 @Aysnc 是如何实现的?【咱们一起读源码】 - 简书 (jianshu.com)

相关文章

网友评论

      本文标题:Spring 中的 @Aysnc 是如何实现的?【咱们一起读源码

      本文链接:https://www.haomeiwen.com/subject/vmtqxdtx.html