热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

@Async代理创建流程

1. 分析@EnableAsync @EnableAsync 上述注解的作用是注册了一个Bean,而这个bean实现了BeanPostProcessor接口,可以参与Bean的初始化。 ...

1. 分析@EnableAsync

@EnableAsync

上述注解的作用是注册了一个Bean,而这个bean实现了BeanPostProcessor接口,可以参与Bean的初始化。

...
@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;
}

该注解可以定义一些属性,且“导入”了一个AsyncConfigurationSelector
该类会注册ProxyAsyncConfiguration

public class AsyncConfigurationSelector extends AdviceModeImportSelector {

    private static final String ASYNC_EXECUTION_ASPECT_CONFIGURATION_CLASS_NAME =
            "org.springframework.scheduling.aspectj.AspectJAsyncConfiguration";

    @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;
        }
    }

}

即注册了AsyncAnnotationBeanPostProcessor,可以完成bean的代理。

@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.getNumber("order"));
        return bpp;
    }
}
  1. 首先AsyncAnnotationBeanPostProcessor完成的代理工作,但是如下图所示,代理工作是在父类中完成的。
@Async代理创建流程
继承关系.png

AsyncAnnotationBeanPostProcessor仅仅实现的是setBeanFactory方法。在此方法中,定义了AsyncAnnotationAdvisor增强器。

@Async代理创建流程
image.png
  1. 那么他的父类AbstractBeanFactoryAwareAdvisingPostProcessor又实现了那些方法?
    由下图可知,它实现了AbstractAdvisingBeanPostProcessor两个方法,大概作用就是筛选“合格”的Advisor以及处理代理工厂ProxyFactory
@Async代理创建流程
image.png
  1. AbstractAdvisingBeanPostProcessor才是实现bean代理的核心方法。
@Async代理创建流程
image.png

2. 如何实现代理

2.1 解决二次代理

代理的实现,依赖的是AbstractAdvisingBeanPostProcessor实现的BeanPostProcessor定义的方法。

在上文中,由于多个自动代理器均代理同一个bean时,可能存在bean的二次代理问题。当然AbstractAdvisingBeanPostProcessor明显考虑到这个问题。

从Spring命名分析:AbstractAdvisingBeanPostProcessor抽象增强后置处理器。
而事务依赖AbstractAutoProxyCreator抽象的自动代理处理器。

AbstractAdvisingBeanPostProcessor发现bean是代理对象时,直接增加Advisor。而AbstractAutoProxyCreator发现bean是代理对象时,会发生二次代理。

2.2 代理源码分析

public abstract class AbstractAdvisingBeanPostProcessor extends ProxyProcessorSupport implements BeanPostProcessor {
    //定义了增强器,由子类setBeanFactory实现。
    @Nullable
    protected Advisor advisor;

    protected boolean beforeExistingAdvisors = false;
    //将“合格”的Bean缓存下来,value=true;
    private final Map, Boolean> eligibleBeans = new ConcurrentHashMap(256);


    public void setBeforeExistingAdvisors(boolean beforeExistingAdvisors) {
        this.beforeExistingAdvisors = beforeExistingAdvisors;
    }

    //并未实现Bean,直接返回。
    @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;
        }
        //代理对象实现了Advised接口,那么直接增加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;
            }
        }
        //若不是代理对象,判断该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());
        }
        return bean;
    }
    //判断bean是否能被增强?(该方法由子类实现)
    protected boolean isEligible(Object bean, String beanName) {
        return isEligible(bean.getClass());
    }

    protected boolean isEligible(Class> targetClass) {
        Boolean eligible = this.eligibleBeans.get(targetClass);
        if (eligible != null) {
            return eligible;
        }
        if (this.advisor == null) {
            return false;
        }
        //判断bean能否使用advisor增强?
        eligible = AopUtils.canApply(this.advisor, targetClass);
        this.eligibleBeans.put(targetClass, eligible);
        return eligible;
    }
    //预处理ProxyFactory对象(该方法由子类实现)
    protected ProxyFactory prepareProxyFactory(Object bean, String beanName) {
        ProxyFactory proxyFactory = new ProxyFactory();
        proxyFactory.copyFrom(this);
        proxyFactory.setTarget(bean);
        return proxyFactory;
    }
    //自定义处理代理工厂
    protected void customizeProxyFactory(ProxyFactory proxyFactory) {
    }
}
@Async代理创建流程
代理对象是否实现了Advised接口.png

当然,我们使用了@Async使用的是AsyncAnnotationBeanPostProcessor完成处理,由2中分析,我们可知子类重写了isEligible/prepareProxyFactory/setBeanFactory方法。继续分析子类重写的方法。

2.3 如何判断bean是否能被Advisor增强?

Spring提供了一个工具方法,AopUtils.canApply()方法,当然,这个方法以及可以脱离Spring容器使用:

@Test  
public void test2(){  
    //定义一个Advisor  
    DefaultPointcutAdvisor advisor=new DefaultPointcutAdvisor();  
    NameMatchMethodPointcut pointcut=new NameMatchMethodPointcut();  
    pointcut.addMethodName("run*");  
    //设置切点  
    advisor.setPointcut(pointcut);  
    System.out.println(AopUtils.canApply(advisor, TService.class));  
    System.out.println(AopUtils.canApply(advisor, XUserService.class));  
}  
@Async代理创建流程
AopUtils.canApply大致流程

@Aysnc校验bean流程

将源码关键部分抽取出来,重点分析 Spring如何校验bean是否能被@Async增强。

public class MyBeanFactoryAware implements BeanFactoryAware {
    @Nullable
    private ConfigurableListableBeanFactory beanFactory;
    private Advisor advisor;
    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = (beanFactory instanceof ConfigurableListableBeanFactory ?
                (ConfigurableListableBeanFactory) beanFactory : null);
        //默认为null
        AsyncAnnotationAdvisor advisor = new AsyncAnnotationAdvisor();
        advisor.setBeanFactory(beanFactory);
        this.advisor=advisor;
    }
    //注解的自动代理
    public boolean isEligible(Class> targetClass){
        return AopUtils.canApply(advisor,targetClass);
    }
}
@Configurable
public class MyConfig {
    @Bean
    public MyBeanFactoryPostProcessor myBeanFactoryPostProcessor(){
        return new MyBeanFactoryPostProcessor();
    }
}
@Slf4j
public class TestProxyDemo {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicatiOnContext=
                new AnnotationConfigApplicationContext(MyConfig.class);
        MyBeanFactoryAware myBeanFactoryAware = (MyBeanFactoryAware)applicationContext.getBean("myBeanFactoryAware");
        boolean eligible = myBeanFactoryAware.isEligible(TService.class);
        boolean uS = myBeanFactoryAware.isEligible(UService.class);
        System.out.println(eligible);
        System.out.println(uS);
    }
}

启动项目,查看bean是否能被增强。
校验方法或类上是否存在@Async注解。

源码位置:org.springframework.aop.support.MethodMatchers.UnionMethodMatcher

@Override  
public boolean matches(Method method, Class> targetClass) {  
    //(判断类上是否存在@Async注解 && 默认true)||(判断target是否是候选bean&& 判断方法上是否存在@Async注解)
    return (matchesClass1(targetClass) && this.mm1.matches(method, targetClass)) ||  
            (matchesClass2(targetClass) && this.mm2.matches(method, targetClass));  
}  

matchesClass1(targetClass)方法

使用org.springframework.aop.support.annotation.AnnotationClassFilter#matches进行验证类上是否存在@Async注解?

@Override  
public boolean matches(Class> clazz) {  
    return (this.checkInherited ? AnnotatedElementUtils.hasAnnotation(clazz, this.annotationType) :  
            clazz.isAnnotationPresent(this.annotationType));  
}  

checkInherited意思是是否检查父类上存在注解?默认true

@Test  
public void test5(){  
    //@Async注解在IAccount上;
    System.out.println(AnnotatedElementUtils.hasAnnotation(AccountImpl.class, Async.class)); //true  
    System.out.println(AccountImpl.class.isAnnotationPresent(Async.class)); //false  
}  

this.mm2.matches(method, targetClass)

源码:org.springframework.aop.support.annotation.AnnotationMethodMatcher#matches

@Override  
public boolean matches(Method method, Class> targetClass) {  
    //该方法和AnnotationClassFilter#matches代码相同;
    if (matchesMethod(method)) {  
        return true;  
    }  
    //如果target是代理对象,直接返回false,即不能再次代理;
    if (Proxy.isProxyClass(targetClass)) {  
        return false;  
    }  
    // The method may be on an interface, so let's check on the target class as well.  
    Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);  
    return (specificMethod != method && matchesMethod(specificMethod));  
}  

2.4 自定义代理对象配置

AbstractAdvisingBeanPostProcessor是一个增强BeanPostProcessor,在处理器内部定义了Advisor

是在org.springframework.scheduling.annotation.AsyncAnnotationBeanPostProcessor#setBeanFactory该方法中定义了Advisor。

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

源码:org.springframework.aop.framework.autoproxy.AbstractBeanFactoryAwareAdvisingPostProcessor

配置ProxyFactory,以便生成Proxy代理对象。

@Override  
protected ProxyFactory prepareProxyFactory(Object bean, String beanName) {  
    if (this.beanFactory != null) {  
        AutoProxyUtils.exposeTargetClass(this.beanFactory, beanName, bean.getClass());  
    }  
    
    ProxyFactory proxyFactory = super.prepareProxyFactory(bean, beanName);  
    if (!proxyFactory.isProxyTargetClass() && this.beanFactory != null &&  
            AutoProxyUtils.shouldProxyTargetClass(this.beanFactory, beanName)) {  
        proxyFactory.setProxyTargetClass(true);  
    }  
    return proxyFactory;  
}  
protected ProxyFactory prepareProxyFactory(Object bean, String beanName) {  
    ProxyFactory proxyFactory = new ProxyFactory();  
    proxyFactory.copyFrom(this);  
    proxyFactory.setTarget(bean);  
    return proxyFactory;  
}  

this对象即AsyncAnnotationBeanPostProcessor。因为实现了ProxyConfig接口(代理配置类)。所以可以影响ProxyFactory的创建过程。

当然,开发者可以修改AsyncAnnotationBeanPostProcessor的BeanDefinition,定义Proxy对象。

@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        BeanDefinition beanDefinition =
                beanFactory.getBeanDefinition(TaskManagementConfigUtils.ASYNC_ANNOTATION_PROCESSOR_BEAN_NAME);
        beanDefinition.getPropertyValues().add("exposeProxy", true);
    }
}

推荐阅读
  • ZSI.generate.Wsdl2PythonError: unsupported local simpleType restriction ... [详细]
  • 本文讨论了在手机移动端如何使用HTML5和JavaScript实现视频上传并压缩视频质量,或者降低手机摄像头拍摄质量的问题。作者指出HTML5和JavaScript无法直接压缩视频,只能通过将视频传送到服务器端由后端进行压缩。对于控制相机拍摄质量,只有使用JAVA编写Android客户端才能实现压缩。此外,作者还解释了在交作业时使用zip格式压缩包导致CSS文件和图片音乐丢失的原因,并提供了解决方法。最后,作者还介绍了一个用于处理图片的类,可以实现图片剪裁处理和生成缩略图的功能。 ... [详细]
  • PHP图片截取方法及应用实例
    本文介绍了使用PHP动态切割JPEG图片的方法,并提供了应用实例,包括截取视频图、提取文章内容中的图片地址、裁切图片等问题。详细介绍了相关的PHP函数和参数的使用,以及图片切割的具体步骤。同时,还提供了一些注意事项和优化建议。通过本文的学习,读者可以掌握PHP图片截取的技巧,实现自己的需求。 ... [详细]
  • Metasploit攻击渗透实践
    本文介绍了Metasploit攻击渗透实践的内容和要求,包括主动攻击、针对浏览器和客户端的攻击,以及成功应用辅助模块的实践过程。其中涉及使用Hydra在不知道密码的情况下攻击metsploit2靶机获取密码,以及攻击浏览器中的tomcat服务的具体步骤。同时还讲解了爆破密码的方法和设置攻击目标主机的相关参数。 ... [详细]
  • 本文介绍了使用PHP实现断点续传乱序合并文件的方法和源码。由于网络原因,文件需要分割成多个部分发送,因此无法按顺序接收。文章中提供了merge2.php的源码,通过使用shuffle函数打乱文件读取顺序,实现了乱序合并文件的功能。同时,还介绍了filesize、glob、unlink、fopen等相关函数的使用。阅读本文可以了解如何使用PHP实现断点续传乱序合并文件的具体步骤。 ... [详细]
  • http:my.oschina.netleejun2005blog136820刚看到群里又有同学在说HTTP协议下的Get请求参数长度是有大小限制的,最大不能超过XX ... [详细]
  • Python正则表达式学习记录及常用方法
    本文记录了学习Python正则表达式的过程,介绍了re模块的常用方法re.search,并解释了rawstring的作用。正则表达式是一种方便检查字符串匹配模式的工具,通过本文的学习可以掌握Python中使用正则表达式的基本方法。 ... [详细]
  • 自动轮播,反转播放的ViewPagerAdapter的使用方法和效果展示
    本文介绍了如何使用自动轮播、反转播放的ViewPagerAdapter,并展示了其效果。该ViewPagerAdapter支持无限循环、触摸暂停、切换缩放等功能。同时提供了使用GIF.gif的示例和github地址。通过LoopFragmentPagerAdapter类的getActualCount、getActualItem和getActualPagerTitle方法可以实现自定义的循环效果和标题展示。 ... [详细]
  • 本文介绍了南邮ctf-web的writeup,包括签到题和md5 collision。在CTF比赛和渗透测试中,可以通过查看源代码、代码注释、页面隐藏元素、超链接和HTTP响应头部来寻找flag或提示信息。利用PHP弱类型,可以发现md5('QNKCDZO')='0e830400451993494058024219903391'和md5('240610708')='0e462097431906509019562988736854'。 ... [详细]
  • Android开发实现的计时器功能示例
    本文分享了Android开发实现的计时器功能示例,包括效果图、布局和按钮的使用。通过使用Chronometer控件,可以实现计时器功能。该示例适用于Android平台,供开发者参考。 ... [详细]
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
  • 本文详细说明了在JavaScript中解决alert弹出窗口文本换行问题的方法。通过给alert弹出的文本添加换行符,可以实现在弹窗中显示多行文本的效果。同时,提供了相关代码示例和注意事项,帮助读者更好地理解和应用这一解决方法。 ... [详细]
  • 解决nginx启动报错epoll_wait() reported that client prematurely closed connection的方法
    本文介绍了解决nginx启动报错epoll_wait() reported that client prematurely closed connection的方法,包括检查location配置是否正确、pass_proxy是否需要加“/”等。同时,还介绍了修改nginx的error.log日志级别为debug,以便查看详细日志信息。 ... [详细]
  • 本文讨论了如何在codeigniter中识别来自angularjs的请求,并提供了两种方法的代码示例。作者尝试了$this->input->is_ajax_request()和自定义函数is_ajax(),但都没有成功。最后,作者展示了一个ajax请求的示例代码。 ... [详细]
  • PDO MySQL
    PDOMySQL如果文章有成千上万篇,该怎样保存?数据保存有多种方式,比如单机文件、单机数据库(SQLite)、网络数据库(MySQL、MariaDB)等等。根据项目来选择,做We ... [详细]
author-avatar
小蚊子
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有