看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注解功能是如何实现的。

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

接下来我们进入这个类

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

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

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

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

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

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

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

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

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

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

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

本文到这里也就结束了。

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

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

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

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

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

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

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

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

文档获取方式:

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

Original: https://www.cnblogs.com/zzyang/p/16320696.html
Author: 三友的java日记
Title: 看Spring源码不得不会的@Enable模块驱动实现原理讲解

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/622222/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • [Java]Java类中的各元素初始化顺序

    先初始化变量,次初始化代码块,再初始化构造器;(先变量,次代码块,再构造器) Original: https://www.cnblogs.com/knqiufan/p/166516…

    Java 2023年6月5日
    054
  • 轻松搞定项目中的空指针异常Caused by: java.lang.NullPointerException: null

    大家在项目测试过程中,是不是经常会碰到这个空指针异常呢Caused by: java.lang.NullPointerException: null 当大家遇到这个问题,大家是怎么…

    Java 2023年5月29日
    0220
  • springboot打包war部署到weblogic,涉及Filter以及Filter中的@Value处理

    基于Maven构建。 1:修改pom.xml配置文件 <packaging>warpackaging> <dependency> <groupI…

    Java 2023年5月30日
    099
  • 常量以及数值问题

    常量定义 在 Java 语言中,主要是利用关键字 final 来定义一个常量。常量一旦被初始化后不能 再更改其值。 常量声明格式为: final type varName = va…

    Java 2023年6月7日
    074
  • Docker(1)

    简介 是什么? 确保应用能够在这些环境中运行和通过质量检测.并且在部署过程中不出现令人头疼的版本、配置问题,也无需重新编写代码和进行故障修复. Docker之所以发展如此迅速,也是…

    Java 2023年6月8日
    069
  • 删除重复值的结点

    删除重复值的结点 问题重述: 给定一个无序单链表的头节点head,删除其中值重复出现的结点 问题分析: 这道题要删除重复值的结点,我们可以想到哈希表,因为哈希表是无序不重复的,我们…

    Java 2023年6月7日
    060
  • IO多路复用

    先说明一个问题:在Java API中提供了两套NIO,一套是针对标准输入输出NIO,另一套就是网络编程NIO。网络编程其实就是多了一个连接的过程,常用在Netty一些框架。本文主要…

    Java 2023年6月7日
    0109
  • 登陆认证框架:SpringSecurity

    最近想给自己的小系统搭建一个登录认证服务,最初是想着一套oauth2权鉴就可以,但是发现这个oauth2只是权鉴,具体的登录认证需要由 SpringSecurity来进行实现。也就…

    Java 2023年6月7日
    067
  • springboot整合xxl-job分布式定时任务【图文完整版】

    一、前言 定时任务有很多种,有一些大的框架也有一些简单的实现。比如常见的: JDK的 Timer&#x548C;TimerTask Quartz异步任务调度框架 分布式定时…

    Java 2023年6月15日
    086
  • InnoDB学习(一)之BufferPool

    我们知道InnoDB数据库的数据是持久化在磁盘上的,而磁盘的IO速度很慢,如果每次数据库访问都直接访问磁盘,显然严重影响数据库的性能。为了提升数据库的访问性能,InnoDB为数据库…

    Java 2023年6月8日
    076
  • Invalid bound statement (not found)出现原因和解决方法

    Invalid bound statement (not found)出现原因和解决方法 前言: 想必各位小伙伴在码路上经常会碰到奇奇怪怪的事情,比如出现Invalid bound…

    Java 2023年6月15日
    054
  • Linux 系统安全加固经验总结

    本文为博主原创,转载请注明出处: 1. 禁止root密码登录 修改 /etc/ssh/sshd_config 中 允许root 用户登录 PermitRootLogin 的值改为 …

    Java 2023年6月8日
    063
  • SpringSecurity中的CSRF解读

    从刚开始学习SpringSecurity时,在配置类中一直存在这样一行代码:http.csrfo.disable() 如果没有这行代码导致用户无法被认证。这行代码的含义是:关闭 c…

    Java 2023年6月5日
    072
  • 序列化表单为json对象,datagrid带额外参提交一次查询 后台用Spring data JPA 实现带条件的分页查询 多表关联查询

    查询窗口中可以设置很多查询条件 表单中输入的内容转为datagrid的load方法所需的查询条件向原请求地址再次提出新的查询,将结果显示在datagrid中 转换方法看代码注释 &…

    Java 2023年5月30日
    0120
  • Windows常用DOS命令

    常见的DOS命令: 关机、重启电脑 shutdown -s (&#x5173;&#x673A;) shutdown -r (&#x5173;&#x9…

    Java 2023年6月9日
    0104
  • [学习笔记] Java常用包装类

    在实际开发过程中,可能需要用到内置数据类型的对象。Java为每个内置数据类型提供对应的包装类。 Number类的子类 所有的数值类型的包装类都是抽象类Number的子类; Inte…

    Java 2023年6月5日
    076
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球