@EnableXXX注解+@Import轻松实现SpringBoot的模块装配

文章目录

    • 前言
    • 原生手动装配
    • 模块装配概述
    • 模块装配的四种方式
      • 准备工作
        • 声明自定义注解
      • 导入普通类
      • 导入配置类
      • 导入ImportSelector
      • 导入ImportBeanDefinitionRegistrar
    • 总结
    • TODO后续--条件装配

在这里插入图片描述

前言

最早我们开始学习或接触过 SSH 或者 SSM 的框架整合,大家应该还记得那些配置文件有多烦吧,又多又不好记真的很让人头大。在处理配置文件的同时,大家是否有想过:如果能有一种方式,可以使用很少的配置,甚至不配置就可以完成一个功能的装载,那岂不是省了很多事?

这个疑问在 SpringBoot 中得以解决,也就是我们常说的自动装配,而这个自动装配的核心技术就是模块装配 + 条件装配。

今天我们这里主要讲解模块装配,条件装配我们后续再讲解!

原生手动装配

通常我们使用 @Configuration + @Bean 注解组合,或者 @Component + @ComponentScan 注解组合,可以实现编程式 / 声明式的手动装配。这两种方式相信大家都肯定会了。

不过,我们思考一个问题:如果使用这两种方式,如果要注册的 Bean 很多,要么一个一个的 @Bean 编程式写,要么就得选好包进行组件扫描,而且这种情况还得每个类都标注好 @Component 或者它的衍生注解才行。面对数量很多的 Bean ,这种装配方式很明显会比较麻烦,需要有一个新的解决方案。

那就是我们接下来要讲的模块装配!

模块装配概述

SpringFramework 3.0 的发布,全面支持了注解驱动开发,随之而来的就是快速方便的模块装配。

模块通常就是一个功能单元,而模块装配就可以理解为把一个模块需要的核心功能组件都装配好,当然如果能有尽可能简便的方式那最好。

SpringFramework 中的模块装配,是在 3.1 之后引入大量 @EnableXXX 注解,来快速整合激活相对应的模块。

在 3.1.5 节中,它有介绍 @EnableXXX 注解的使用,并且它还举了不少例子,这里面不乏有咱可能熟悉的:

  • EnableTransactionManagement :开启注解事务驱动
  • EnableWebMvc :激活 SpringWebMvc
  • EnableAspectJAutoProxy :开启注解 AOP 编程
  • EnableScheduling :开启调度功能(定时任务)

另外比如:我们常用的@SpringBootApplication注解中用于开启自动注入的@EnableAutoConfiguration,开启异步方法的@EnableAsync,开启将配置文件中的属性以bean的方式注入到IOC容器的@EnableConfigurationProperties等。

其实 @Enable*注解很简单,随便找一个注解,点进去一看就能恍然大悟,它的所有核心 都在@Import 注解当中。 所有真正核心的 是@Import注解,由它去加载它自己对应的配置类,然后启动他的功能。

比如我们上面的EnableAsync,它会将AsyncConfigurationSelector放入容器中,当Spring启动,会执行selectImports(AnnotationMetadata annotationMetadata)方法,在这个方法中我们做了某些处理,使得和 @Enable*搭配使用的注解生效。

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

那有人会说@Import注解就可以了,还要Enable*注解干嘛,我直接使用@Import注解去加载就好了,这不是多此一举吗? 看看下面的好处就知道了

  • 除了桥梁的作用,它还可以携带上一些参数:在解析处理这个 注解的时候,可以从这里拿到一些 自定义配置的参数,去做相关的操作。

  • 启用这个功能可能需要更多的 类加载,还有要其它注解去配和,如果不将其包装到 @Enable*中,那对开发者来说,配置起来又相对麻烦了许多,将其包装到一起,只需要记住使用这一功能记住这个注解即可。极大的方面!!。

  • 将功能做组建抽离开来,降低耦合性。


模块装配的四种方式

先记住使用模块装配的核心原则:自定义注解 + @Import 导入组件。
在这里插入图片描述

准备工作

声明自定义注解

我们自定义一个注解用来是否允许来进行日志记录

@Documented
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface EnableLog {}

模块装配需要一个最核心的注解是 @Import ,它要标注在 @EnableLog 上。不过这个 @Import 中需要传入 value 值,点开看一眼它的源码吧:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {/*** {@link Configuration @Configuration}, {@link ImportSelector},* {@link ImportBeanDefinitionRegistrar}, or regular component classes to import.*/Class<?>[] value();
}

文档注释已经写得非常明白了:它可以导入配置类ImportSelector 的实现类ImportBeanDefinitionRegistrar 的实现类,或者普通类。咱这里先来快速上手,所以我们先选择使用普通类导入。

导入普通类

注意只有在Spring 4.2之后,@Import可以直接指定实体类,加载这个类定义到context中。

注意我们的MyLog是没有任何注解的

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import(MyLog.class)
public @interface EnableLog {}public calss MyLog{...}

这样就代表,如果标注了 @EnableLog 注解,就会触发 @Import 的效果,向容器中导入一个 MyLog 类型的 Bean


如何进行生效?

在使用自定义的Enable注解需要搭配Spring原生的 @Configuration 进行使用,单纯只有@EnableLog是不行的

如果是SpringBoot项目,可以直接放在@SpringBootApplication注解的类上面,有人会问为什么放在这里可以呢?原因就是 @SpringBootConfiguration注解上面配置了 @Configuration 注解。@SpringBootApplication就相当于一个@Configuration注解,所以我们自定义的Enable注解可以直接放在@SpringBootApplication,当然也可以自定义一个用@Configuration修饰的类上面。

下面的例子都需要这个MyLogConfiguration 配置类,后面就不进行赘述了。

@Configuration
@EnableLog
public class MyLogConfiguration {}

经过这样,运行发现我们的spring容器中已经有了MyLog类

public class LogApplication {public static void main(String[] args) throws Exception {AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(MyLogConfiguration.class);Boss boss = ctx.getBean(MyLog.class);System.out.println(boss);}
}

导入配置类

如果需要直接导入一些现有的配置类,使用 @Import 也可以直接加载进来。

@Configuration
public class LogBeanConfiguration {@Beanpublic MyLog myLog() {return new MyLog();}@Beanpublic LogUtil logUtil() {return new LogUtil();}}

然后只需要在 @EnableTavern@Import 中把这个配置类加上即可:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import(MyLog.class,LogBeanConfiguration.class)
public @interface EnableLog {}

运行发现,我们容器打印出两个MyLog类:,LogBeanConfiguration 配置类也被注册到 IOC 容器成为一个 Bean 了。

    public static void main(String[] args) throws Exception {AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(MyLogConfiguration.class);Stream.of(ctx.getBeanDefinitionNames()).forEach(System.out::println);System.out.println("--------------------------");Map<String, MyLog> myLogs = ctx.getBeansOfType(MyLog.class);myLogs.forEach((name, myLog) -> System.out.println(myLog));}

导入ImportSelector

注意,我们可能还会看到DeferredImportSelector这个注解,这个注解其实是继承了ImportSelector
他们算是一类接口,只是执行的时间不同而已。看Deferred这个单词意思就知道了,Deferred只是进行延迟了。

我们的 ImportSelector 可以导入普通类和配置类:

注意,selectImports 方法的返回值是一个 String 类型的数组,它这样设计的目的是什么呢?咱来看看 selectImports 方法的文档注释:

根据导入的 @Configuration 类的 AnnotationMetadata 选择并返回要导入的类的类名。也就是可以根据AnnotationMetadata注解条件在进行匹配

public class MyLogImportSelector implements ImportSelector {@Overridepublic String[] selectImports(AnnotationMetadata importingClassMetadata) {return new String[] {MyLog.class.getName(), LogBeanConfiguration.class.getName()};}
}
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import(MyLog.class,LogBeanConfiguration.class,MyLogImportSelector.class)
public @interface EnableLog {}

运行后我们会发现,有4个MyLog.class类,MyLog.class一个,LogBeanConfiguration.class一个,MyLogImportSelector.class两个

导入ImportBeanDefinitionRegistrar

如果说 ImportSelector 更像声明式导入的话,那 ImportBeanDefinitionRegistrar 就可以解释为编程式向 IOC 容器中导入 Bean 。不过由于它导入的实际是 BeanDefinition ( Bean 的定义信息)。我们对 ImportBeanDefinitionRegistrar 有一个快速的使用入门即可。

简单解释下,这个 registerBeanDefinition 方法传入的两个参数,第一个参数是 Bean 的名称(id),第二个参数中传入的 RootBeanDefinition 要指定 Bean 的字节码( .class )。

public class MyLogRegistrar implements ImportBeanDefinitionRegistrar {@Overridepublic void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {registry.registerBeanDefinition("myLog", new RootBeanDefinition(MyLog.class));}
}
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import(MyLog.class,LogBeanConfiguration.class,MyLogImportSelector.class,MyLogRegistrar.class)
public @interface EnableLog {}

运行后我们会发现,有5个MyLog.class类,MyLog.class一个,LogBeanConfiguration.class一个,MyLogImportSelector.class两个

注意这里 MyLogRegistrar 本身没有注册到 IOC 容器中。

总结

  • Enable类型的注解从Spring原生的和自己拓展的来看,相当于一个开关。增加这个注解就开启了一个功能,需要搭配其他的注解来使用,例如:@EnableAsync搭配@Async注解,@EnableTransactionManagement搭配@Transactional注解使用
  • Enable类型注解生效需要搭配@Configuration注解
  • Enable类型注解的实现需要搭配注解@Import导入,可以导入普通类、配置类,而更高级一点的功能实现需要实现DeferredImportSelector、ImportSelector、ImportBeanDefinitionRegistrar三个接口中一个。

TODO后续–条件装配

通过模块装配,咱可以通过一个注解,一次性导入指定场景中需要的组件和配置。那么只靠模块装配的内容,就可以把这些装配都考虑到位吗?

比如只要配置类中声明了 @Bean 注解的方法,那这个方法的返回值就一定会被注册到 IOC 容器成为一个 Bean 。但是有时候我们需要根据某些条件进行判断呢?这就需要我们的条件装配了,具体篇幅有限,后续在进行讲解

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/591624.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Redis 与 Spring: 解决序列化异常的探索之旅

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…

YOLOv8改进 | 注意力篇 | ACmix自注意力与卷积混合模型(提高FPS+检测效率)

一、本文介绍 本文给大家带来的改进机制是ACmix自注意力机制的改进版本&#xff0c;它的核心思想是&#xff0c;传统卷积操作和自注意力模块的大部分计算都可以通过1x1的卷积来实现。ACmix首先使用1x1卷积对输入特征图进行投影&#xff0c;生成一组中间特征&#xff0c;然后根…

ant-design-vue的form表单全局禁用不生效

文章目录 一、问题二、解决2.1、4.0之前的版本2.2、4.0开始的版本 三、最后 一、问题 ​ 实际使用ant-design-vue在开发表单的时候或许会遇到编辑与查看的需求&#xff0c;但是查看的时候表单不允许编辑&#xff0c;ant-design-vue的官方是没有像element一样提供全局disabled属…

Tomcat 安装和运行教程

文章目录 一、Tomcat 安装1.1 选择合适的 Tomcat 版本1.2 下载 Tomcat1.3 配置环境变量 二、 运行 Tomcat2.1 启动 Tomcat2.2 关闭 Tomcat 参考资料 一、Tomcat 安装 1.1 选择合适的 Tomcat 版本 Apache Tomcat 是 Jakarta EE&#xff08;正式JavaEE&#xff09;技术子集的开…

Java经典框架之SpringBoot

SpringBoot Java 是第一大编程语言和开发平台。它有助于企业降低成本、缩短开发周期、推动创新以及改善应用服务。如今全球有数百万开发人员运行着超过 51 亿个 Java 虚拟机&#xff0c;Java 仍是企业和开发人员的首选开发平台。 课程内容的介绍 1. SpringBoot基础 2. Spring…

第7课 利用FFmpeg将摄像头画面与麦克风数据合成后推送到rtmp服务器

上节课我们已经拿到了摄像头数据和麦克风数据&#xff0c;这节课我们来看一下如何将二者合并起来推送到rtmp服务器。推送音视频合成流到rtmp服务器地址的流程如下&#xff1a; 1.创建输出流 //初始化输出流上下文 avformat_alloc_output_context2(&outFormatCtx, NULL, &…

杜笙MB-115up抛光树脂(出水18兆欧)

TULSIONMB-115UP是一种高阶核子级抛光树脂&#xff0c;由核子级强酸型阳离子TulsimerMB115和强碱阴离子交换树脂A33按一定比例混合而成。这种树脂具有独特的结构和性能&#xff0c;能够有效地去除材料表面的污渍和杂质&#xff0c;提高材料的表面质量和光泽度。 首先&#xff0…

【Spring实战】15 Logback

文章目录 1. 依赖2. 配置3. 打印日志4. 启动程序5. 验证6. 调整日志级别7. 代码详细总结 Spring 作为一个现代化的 Java 开发框架&#xff0c;提供了很多便利的功能&#xff0c;其中包括灵活而强大的日志记录。本文将介绍如何结合 Spring 和 Logback 配置和使用日志&#xff0c…

基于mediapipe的人体姿态估计模型——没有GPU依然速度飞起

关于人体姿态检测模型,我们前期也介绍过了很多相关的模型,比如基于Yolo-NAS的姿态检测以及基于YOLOv8的人体姿态检测,而人体姿态估计一直是计算机视觉任务中比较重要的一个模型。但是基于YOLO系列的人体姿态检测模型需要较大的算力,且很难在CPU模型上快速的运行。 基于medi…

HTML5 和 CSS3 新特性(常用)

HTML5 的新特性 HTML5 的新增特性主要是针对于以前的不足&#xff0c;增加了一些新的标签、新的表单和新的表单属性等。 这些新特性都有兼容性问题&#xff0c;基本是 IE9 以上版本的浏览器才支持&#xff0c;如果不考虑兼容性问题&#xff0c;可以大量使用这 些新特性。 HTML…

【二叉树的顺序结构及实现一-堆】

文章目录 一、二叉树的顺序结构二、堆的概念及结构三、堆的实现(以小堆为例)1、堆的结构体2、堆的初始化->void HeapInit(HP* hp);3、堆的销毁->void HeapDestroy(HP* hp);4、堆的判空->bool HeapEmpty(HP* hp);5、取堆顶的数据->HPDataType HeapTop(HP* hp);6、堆…

抖店新手该如何运营?

我是电商珠珠 在抖店开好之后&#xff0c;大部分新手都不知道怎么去运营&#xff0c;今天&#xff0c;我就来给大家详细的讲一下。 第一步&#xff0c;店铺基础设置 我一直跟我的学生讲&#xff0c;一定要懂基本流程&#xff0c;只有前期将流程跑通了后期才可以毫无压力。 …

Java基础综合练习(飞机票,打印素数,验证码,复制数组,评委打分,数字加密,数字解密,抽奖,双色球)

练习一&#xff1a;飞机票 需求: ​ 机票价格按照淡季旺季、头等舱和经济舱收费、输入机票原价、月份和头等舱或经济舱。 ​ 按照如下规则计算机票价格&#xff1a;旺季&#xff08;5-10月&#xff09;头等舱9折&#xff0c;经济舱8.5折&#xff0c;淡季&#xff08;11月到来…

【algorithm】自动驾驶常见常考的几个模型和推导,顺便总结自己遇到的考题经验不断更新之———控制版

写在前面 本来快达成目标了&#xff0c;没想到公司遭受了问题&#xff0c;公司和同事我感觉还是挺好的&#xff0c;有国企的正规也有小企业的灵活&#xff0c;大家都很有学习欲望。 作为本次再次复习回忆如下&#xff1a; 把之前面试准备的 机器学习&#xff08;基本搬运到CSD…

JVM篇:JVM的简介

JVM简介 JVM全称为Java Virtual Machine&#xff0c;翻译过来就是java虚拟机&#xff0c;Java程序&#xff08;Java二进制字节码&#xff09;的运行环境 JVM的优点&#xff1a; Java最大的一个优点是&#xff0c;一次编写&#xff0c;到处运行。之所以能够实现这个功能就是依…

电脑突然不能使用win+x后的快捷键的解决方法

在一次使用电脑后我习惯性的winxuh进行休眠&#xff0c;但是失败了&#xff0c;我发现winx后并没有出现曾经常用的快捷键方式。 左边图片显示的是正常情况。我遇到的情况是图片右边快捷键位没有了&#xff0c;并且也不能进行快捷操作。 国内的网站我都搜索过了&#xff0c;甚至…

outlook邮箱群发邮件方法?邮箱如何群发?

outlook邮箱群发邮件如何使用&#xff1f;QQ邮箱设置群发的步骤&#xff1f; Outlook邮箱群发邮件&#xff1a;必要性 Outlook邮箱作为全球广泛使用的邮件服务之一&#xff0c;不仅提供了便捷的邮件收发功能&#xff0c;还支持多种附件、日历提醒及强大的联系人管理。Outlook…

Python 实现给 pdf 文件自动识别标题并增添大纲

一、背景&#xff1a; 客户方提供过来一个开放平台的pdf文档&#xff0c;文档里有几十个接口&#xff0c;没有大纲和目录可以定位到具体内容&#xff0c;了解整体的API功能&#xff0c;观看体验极度差劲&#xff0c;所以想使用Python代码自动解析pdf文档&#xff0c;给文档增添…

某人寿保险公司基础架构云化与小机数仓下移实践

随着数据中心 IT 基础架构的不断演进&#xff0c;云计算、大数据、移动互联的需求日益高涨&#xff0c;快速敏捷、易于维护以及扩展性&#xff0c;逐渐成为金融机构在升级数据中心时重点考虑的方面。 某人寿保险公司&#xff08;以下简称“客户”&#xff09;过往采用传统三层架…

PS插件一键生成超治愈向日葵花海

金黄色的向日葵总能给人带来治愈的感觉&#xff0c;仿佛在这里能够疗愈心灵所有的伤口。今天我们通过START AI来生成一片美丽的向日葵花海~ 这是小编使用的关键词&#xff0c;负面词需要填写你不想要拥有的&#xff0c;能够让生成的结果更贴合你的想法 最后的生成效果就如下图…