• 看Spring源码不得不会的@Enable模块驱动实现原理讲解


    这篇文章我想和你聊一聊 spring的@Enable模块驱动的实现原理。

    在我们平时使用spring的过程中,如果想要加个定时任务的功能,那么就需要加注解@EnableScheduling,如果想使用异步的功能,那就要加@EnableScheduling注解,其实这类注解就是属于@Enable模块。

    那么@Enable模块到底有什么功能?

    模块是指具备相同领域的功能组件集合,组合所形成一个独立的单元。比如Web MVC模块、AspectJ代理模块Caching缓存模块,JMX(Java管理扩展)、Async异步处理模块等。所谓模块装配,简而言之就是,通过@EnableXXX注解实现一个开关,这个开关决定是否开启某个功能模块的所有组件的自动化配置。

    那么@EnableXXX注解是如何生效的?

    其实@EnableXXX只是一个名字,通过这个名字让人知道实现了什么功能,其实这个注解叫什么名字其实是无所谓的,就算不叫@EnableXXX都行,只不过spring内部都叫@EnableXXX,我们就习惯叫@Enable模块,所以核心不是这个注解,而是注解实现的套路。

    接下来我们来说说这个注解功能实现的套路

    一般@EnableXXX注解是通过@Import实现具体的功能(@EnableXXX注解上加个@Import注解),@Import才是@EnableXXX起效果的核心功能。@Import大家都知道,就是往容器里面注入一个配置类,但是这个配置类可是有讲究的。

    这里我直接上源码,带你看看@Import注解功能是如何实现的。

    @Import注解的功能是在org.springframework.context.annotation.ConfigurationClassParser类processImports方法处理的。接下来我们就来解读一下实现的核心部分。

    首先判断@Import注解导入的是配置类有没有实现ImportSelector接口,实现的话就就调用ImportSelector的selectImports方法,这个方法返回的是一批配置类的全限定名,然后继续解析这些配置类。

    ImportSelector接口的作用其实就是往spring容器中再次注入一批配置类。

    如果没有实现ImportSelector接口,那么再判断有没有实现ImportBeanDefinitionRegistrar,有的话就会调用ImportBeanDefinitionRegistrar的registerBeanDefinitions方法,通过名字也可以判断出,其实就是往spring容器注入一些BeanDefinition。

    ImportBeanDefinitionRegistrar的作用其实很简单,就是往spring容器注入一些BeanDefinition。如果不是很清楚BeanDefinition是什么,欢迎查看Spring bean到底是如何创建的?(上)这篇文章,有讲解。

    如果这两个接口都没有实现,那么就当时一个普通的配置类进行解析。

    读完@Import实现的源码,我们再来总结回顾@Import的作用。

    @Import注解,就是导入一个配置类,但是这个配置类分为不同的情况。如果这个配置类实现了ImportSelector接口,那么就会调用selectImports方法的实现,获取一批配置类的全限定名,然后再解析配置类;如果实现了@Import注解导入的配置类实现类ImportBeanDefinitionRegistrar,那么就会调用registerBeanDefinitions方法的实现,这个方法可以往容器中注入BeanDefinition;最后如果都没实现,那么就按照一个普通的配置类来解析。

    所以基于这么一套配置类解析的规则,就可以实现往容器中注入一些bean,通过这些bean来完成某块功能的实现。

    @EnbaleAsync注解的是如何起作用的

    懂了@Enbale模块驱动的基本原理,接下来我们举个例子,来看看@EnbaleAsync注解是如何实现的。

    @EnbaleAsync注解上通过@Import注解导入了AsyncConfigurationSelector类

    接下来我们进入这个类

    一看源码,就发现继承了AdviceModeImportSelector,其实这个类实现了ImportSelector接口,附上源码

    其实这个对于ImportSelector接口的实现就是解析注解的属性,然后拿到一个AdviceMode,再调用一个模板方法selectImports,这个方法主要子类来实现,所以我们来看看AsyncConfigurationSelector的实现。

    这个adviceMode是注解@EnableAaync注解中的属性mode(),你可以自己翻一下,默认是PROXY,所以这个方法其实就是返回ProxyAsyncConfiguration类的全限定名,其实就是往容器中添加了ProxyAsyncConfiguration配置类。

    我们进入这个配置类看一下

    其实就是往容器中注入一个AsyncAnnotationBeanPostProcessor,通过名字可以看出这是一个BeanPostProcessor,也就是在bean的生命周期的某个节点来处理@Aysnc注解,如果有不懂BeanPostProcessor的同学可以看看Spring bean到底是如何创建的?(上)和 Spring bean到底是如何创建的?(下)这两篇文章,里面有详细的说明。至于AsyncAnnotationBeanPostProcessor的实现我们就不再继续深究了,有兴趣的同学可以自行点进去看看。

    所以说白了,@EnbaleAsync注解的主要作用就是往容器中添加一个可以住了@Async注解的AsyncAnnotationBeanPostProcessor,在bean创建的某个阶段起到作用。

    看完@EnableAsync注解的实现,你也可以仿照这个注解的实现来自己实现一个@Enable来实现某个特定的功能。

    本文到这里也就结束了。

    如果我的文章对你有所帮助,还请帮忙点赞、在看、转发一下,你的支持会激励我输出更高质量的文章,码字不易,非常感谢!

    如果你想联系我,欢迎关注我的个人的微信公众号三友的java日记,公众号会持续推送优质的技术文章,期待与你一起进步。

     

    最近花了一个月的时间,整理了这套并发编程系列的知识点。涵盖了 volitile、synchronized、CAS、AQS、锁优化策略、同步组件、数据结构、线程池、Thread、ThreadLocal,几乎覆盖了所有的学习和面试场景,如图。

     

     

     

    文档获取方式

    链接:https://pan.baidu.com/s/129wZe3ywAUsjOqTU037Kmg
    提取码:aps9

  • 相关阅读:
    【ICCV2023】DECO:野外环境场景下的 3D 人体-场景的接触估计
    数据结构与算法之美学习笔记:24 | 二叉树基础(下):有了如此高效的散列表,为什么还需要二叉树?
    shell(19): shell脚本for循环(nmon监控)2
    综合案例-数据可视化-柱状图
    Spire.office for Java 7.8.0
    RNA-Seq 笔记 [4]
    SpringCloudAlibaba——Sentinel
    python:神经网络的卷积核,权重矩阵长什么样子?
    Zabbix技术分享——使用docker-compose快速部署zabbix监控系统
    Spring Ioc源码分析系列--@Autowired注解的实现原理
  • 原文地址:https://www.cnblogs.com/zzyang/p/16320696.html