【原理篇】二、Bean加载控制

文章目录

  • 1、编程式Bean加载控制
  • 2、注解式Bean加载控制
  • 3、@Conditional派生注解
  • 4、Bean依赖的属性配置

Bean的加载控制指根据特定情况对bean进行选择性加载以达到适用于项目的目标

上篇Bean声明的方式中,后4种可以实现对Bean加载的控制,分别是:

  • AnnotationConfigApplicationContext调用register方法
  • @Import导入ImportSelector接口
  • @Import导入ImportBeanDefinitionRegistrar接口
  • @Import导入BeanDefinitionRegistryPostProcessor接口

且上篇中已演示了部分对Bean加载的控制,这里演示编程式和注解式两种。

1、编程式Bean加载控制

下面实现:当A类被加载了,我才将B类的Bean加载。

public class MyImportSelector implements ImportSelector {@Overridepublic String[] selectImports(AnnotationMetadata importingClassMetadata) {try {Class<?> clazz = Class.forName("com.plat.bean.Mouse");if(clazz != null) {  //如果老鼠的类被加载了(注意不关心是不是Bean,只看是不是类加载了)return new String[]{"com.itheima.bean.Cat"};  //那就把猫这个类注册成Bean}} catch (ClassNotFoundException e) {//e.printStackException();return new String[0];    //条件类老鼠不存在时,返回一个空数组}return null;}
}

2、注解式Bean加载控制

上面代码里的判断的逻辑对所有类都大同小异,因此考虑抽成一组注解,公共逻辑部分用AOP去实现就好。Spring提供了@Conditional注解:

在这里插入图片描述

注解的属性类型是一个Condition接口或者其子类,且Condition接口有抽象方法需要实现,这样写还是很繁琐。因此常使用@Conditional注解的派生注解。注意很多派生注解都是SpringBoot的。

<!--非Boot项目记得导入SpringBoot的起步依赖才能找到这些派生注解-->
<dependency>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter</artifactId>    <version>2.5.4</version>
</dependency>
<!--注意boot的starter包含Spring的一些依赖,比如spring-context,若旧项目是Spring项目,可直接注释掉相关依赖,省的依赖冲突,版本混乱-->

在这里插入图片描述

以下分别整理这些派生注解。

3、@Conditional派生注解

@ConditionalOnClass:有这个类了(是不是Bean无所谓),就加载下面这个Bean

@Component
@ConditionalOnClass(Mouse.class)
public class Cat{}
//有老鼠这个类被加载了(注意强调的是类,不管你是不是Bean),就加载Cat这个Bean

使用注解的value属性,这么写有点此地无银三百两了,编译器报错的时候,即导包失败,就说明没这个类,那还判断个啥,所以常用name属性,而不是直接class

@Component
@ConditionalOnClass(name = "com.plat.po.Mouse")
public class Cat{}

@ConditionalOnMissingClass:没这个时(是不是Bean无所谓),就加载下面这个Bean

@Component
@ConditionalOnMissingClass("com.plat.po.Wolf")   //没有狼来时,加载猫成为一个Bean
public class Cat{}

这样控制Bean加载的一个很经典的例子就是DataSource,如下:即只有用到了MySQL的驱动类时,再加载dataSource的Bean

public class SpringConfig {@Bean@ConditionalOnClass(name = "com.mysql.jdbc.Driver")public DruidDataSource dataSource(){DruidDataSource ds = new DruidDataSource();return ds;}
}

再往大了想,有一个技术框架的jar包,当你用到某个标志类,那就加载该技术所有的Bean,否则就不加载,此时,使用者只需做一些简单的配置即可。

@ConditionalOnBean : 有这个Bean时,才加载下面的这个Bean

public class SpringConfig {@Bean@ConditionalOnBean(name="jerry")@ConditionalOnMissingBean(name = "com.plat.po.Dog")public Cat tom(){return new Cat();}
}//不关心有没有老鼠的类被加载,而是要求有叫杰瑞的Bean,且没有狗的Bean,Tom才加载到Ioc中成为Bean

@ConditionalOnNotWebApplication和@ConditionalOnWebApplication :非Web或者Web环境下再加载

注意,这些派生注解同时出现在同一个类上方时,它们之间是且的关系。

4、Bean依赖的属性配置

结论:当业务Bean运行需要一些属性时,抽取一个独立的属性类xxProperties,读取配置文件信息

用一个循序渐进的示例来体验属性配置,先准备几个demo类:

@Data
public class Cat{private String name;private Integer age;
}
@Data
public class Mouse{private String name;private Integer age;
}
//猫和老鼠卡通类
@Component
public class CartoonCatAndMouse{private Cat cat;private Mouse mouse;//提供个构造方法给两个属性赋值,不然默认null,下面会空指针public CartoonCatAndMouse(){cat = new Cat();cat.setName("tom");cat.setAge(3);mouse= new Mouse();mouse.setName("jerry");mouse.setAge(3);}public void play(){System.out.println(cat.getAge()+"岁的"+cat.getName()+"与"+mouse.getAge()+"岁的"+mouse.getName()+"打起来了");}
}
//启动类中调用下play方法
@SpringBootApplication
public class App{public static void main(String[] args){ConfigurableApplicationContext ctx = pringApplication.run(app.class);CartoonCatAndMouse bean = ctx.getBean(CartoonCatAndMouse.class);bean.play();}
}

此时,配置都硬编码了,显然不合理。

优化第一步:引入yaml配置并@ConfigurationProperties读取

cartoon:cat:name: tomage: 3mouse:name: jerryage: 4
@Component
@ConfigurationProperties(prefix = "cartoon")
//加个set,不然cat属性和mouse属性为null
@Data  
public class CartoonCatAndMouse{private Cat cat;private Mouse mouse;public void play(){System.out.println(cat.getAge()+"岁的"+cat.getName()+"与"+mouse.getAge()+"岁的"+mouse.getName()+"打起来了");}
}

此时,如果yaml配置中没有相关配置,则对应的对象为null,进而空指针。也就是说,一加@ConfigurationProperties(prefix = “cartoon”),我的类和yaml配置绑死了,没配置,类都受影响。

优化第二步:引入独立配置类CartoonProperties

@ConfigurationProperties(prefix = "cartoon")
@Data
//旧知识点,读取yaml的类的对象必须受Spring容器管控,否则,即使拿到yaml值也无法set给你
@Component
public class CartoonProperties {private Cat cat;private Mouse mouse;
}
@Component
@Data  
public class CartoonCatAndMouse{private Cat cat;private Mouse mouse;//构造器注入了,用@Autowired也行private CartoonProperties cartoonProperties;public void play(CartoonProperties cartoonProperties){this.cartoonProperties = cartoonProperties;cat = new Cat();cat.setName(cartoonProperties.getCat()!=null && StringUtils.hasText(cartoonProperties.getCat().getName())?cartoonProperties.getCat().getName():"tom");  //有则用,无则用默认值//Mouse对象同样写法,略System.out.println(cat.getAge()+"岁的"+cat.getName()+"与"+mouse.getAge()+"岁的"+mouse.getName()+"打起来了");}
}

此时,有个缺点,CartoonProperties类不管用不用,都被强制加载成一个Bean了,但去掉@Component,只留@ConfigurationProperties语法错误 ⇒ 用@EnableConfigurationProperties

优化第三步:@EnableConfigurationProperties,改掉强制加载Bean

@ConfigurationProperties(prefix = "cartoon")
@Data
public class CartoonProperties {private Cat cat;private Mouse mouse;
}

@ConfigurationProperties和@EnableConfigurationProperties,前者是做属性绑定的,后者是开启属性绑定,并设定对应的目标是谁

@Component  //这个Component也可以去掉,用的时候@Import(CartoonCatAndMouse.class)
@Data  
//即当我加载CartoonCatAndMouse时,就用CartoonProperties.class,并把CartoonProperties类加载成Bean
@EnableConfigurationPropertiesCartoonProperties.class)   
public class CartoonCatAndMouse{private Cat cat;private Mouse mouse;//重复代码,略....

这套模式的亮点有以下几个:

  • 合理的加载配置文件,即你配置了就用你的,没配就用默认值来工作
  • 对于属性类xxxProperties不用强制配置成Bean,使用@EnableConfigurationProperties
  • 对于业务功能的Bean,通常使用@Import将一个类加载成Bean,来解耦强制加载Bean,以降低Spring容器管理Bean的工作量以及强度

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

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

相关文章

AI创作系统ChatGPT商业运营系统源码+支持GPT4/支持ai绘画

一、AI创作系统 SparkAi创作系统是基于OpenAI很火的ChatGPT进行开发的Ai智能问答系统和Midjourney绘画系统&#xff0c;支持OpenAI-GPT全模型国内AI全模型。本期针对源码系统整体测试下来非常完美&#xff0c;可以说SparkAi是目前国内一款的ChatGPT对接OpenAI软件系统。那么如…

陈海波:OpenHarmony技术领先,产学研深度协同,生态蓬勃发展

11月4日&#xff0c;以“技术筑生态&#xff0c;智联赢未来”为主题的第二届OpenHarmony技术大会在北京隆重举办。本次大会由OpenAtom OpenHarmony&#xff08;简称“OpenHarmony"&#xff09;项目群技术指导委员会&#xff08;TSC&#xff09;主办&#xff0c;由华为技术…

智能网联汽车基础软件信息安全需求分析

目录 1.安全启动 2.安全升级 3.安全存储 4.安全通信 5.安全调试 6.安全诊断 7.小结 1.安全启动 对于MCU&#xff0c;安全启动主要是以安全岛BootROM为信任根&#xff0c;在MCU启动后&#xff0c;用户程序运行前&#xff0c;硬件加密模块采用逐级校验、并行校验或者混合校…

uniapp使用vue3和ts开发小程序自定义tab栏,实现自定义凸出tabbar效果

要实现自定义的tabbar效果&#xff0c;可以使用自定义tab覆盖主tab来实现&#xff0c;当程序启动或者从后台显示在前台时隐藏自带的tab来实现。自定义一个tab组件&#xff0c;然后在里面实现自定义的逻辑。 组件中所使用的组件api可以看&#xff1a;Tabbar 底部导航栏 | uView…

从0到1的Springcloud Alibaba项目,一篇入门!!!

1、新建项目 我们用maven管理项目 第一步&#xff1a;选择maven 第二步&#xff1a;项目命名&#xff0c;项目路径 第三步&#xff1a;进入项目&#xff0c;把src文件夹删掉&#xff08;不删也没事&#xff0c;主要是用不到这个文件夹&#xff09; 2、引入项目依赖 在父项目…

【广州华锐互动】智能楼宇3D数字化展示,实现对建筑物的实时监控和管理

随着科技的不断发展&#xff0c;人们对于生活品质的要求也在不断提高。在这个信息爆炸的时代&#xff0c;如何将复杂的数据以直观、生动的方式呈现给用户&#xff0c;已经成为了一个重要的课题。智能楼宇3D数字化展示作为一种新型的建筑科技&#xff0c;正逐渐成为行业的新宠&a…

【图像分类】【深度学习】【Pytorch版本】VggNet模型算法详解

【图像分类】【深度学习】【Pytorch版本】VggNet模型算法详解 文章目录 【图像分类】【深度学习】【Pytorch版本】VggNet模型算法详解前言VggNet讲解感受野感受野的计算公式3x3的卷积核的使用VggNet模型结构 VGGnet Pytorch代码完整代码总结 前言 Vgg(Visual Geometry Group)是…

养老院展示服务预约小程序的作用是什么

养老院无论在哪个城市都有很高需求度&#xff0c;不少银发人群会因为种种原因而前往&#xff0c;而养老院近些年来各种服务也比较完善&#xff0c;增加了客户信任度及接受度&#xff0c;但对院方来说&#xff0c;也存在着一些痛点&#xff1a; 1、品牌传播服务呈现难 养老院也…

网络运维Day01

文章目录 环境准备OSI七层参考模型什么是协议&#xff1f;协议数据单元(PDU)设备与层的对应关系什么是IP地址&#xff1f;IP地址分类IP的网络位和主机位IP地址默认网络位与主机位子网掩码默认子网掩码查看IP地址安装CISCO汉化CISCO(可选操作) CISCO之PC机器验证通信 CISCSO之交…

PMI-ACP(103:57- 103)

57/103 高绩效敏捷团队的特征 参与式指导有效的决策开放和清晰的沟通价值多样性相互信任管理冲突清楚目标明确定义角色 和 职责协调关系积极的氛围 58/103 创建授权团队 敏捷强调 具备授权和积极性 的自我管理团队&#xff0c;他们需要对项目成果充分负责&#xff0c;授权是…

软考 -- 计算机学习(3)

文章目录 一、软件测试基础1.1 基本概念1.2 软件测试模型1.3 软件测试的分类 二、基于规格说明的测试技术(黑盒)2.1 重要的测试方法1. 等价类划分法2. 边界值法3. 判定表法4. 因果图法 2.2 其他测试方法 三、基于结构的测试技术(白盒)3.1 静态测试3.2 动态测试 一、软件测试基础…

配置阿里云镜像加速器 -docker

1.百度aliyun 2.找到镜像服务ACR 3.搞一个个人版&#xff0c;身份验证一下就行了很简单 4.找到镜像加速器Centos 5.执行下面4条命令&#xff1a;4条命令直接从上面操作文档中粘贴&#xff0c;不容易出错 sudo mkdir -p /etc/docker sudo tee /etc/docker/daemon.json <<…

Win10 + VS017 编译SQLite3.12.2源码

参考&#xff1a; [1] WIN10 VS2019下编译GDAL3.0PROJ6SQLite_gdal 3 win10编译-CSDN博客 [2] 如何编译SQLite-How To Compile SQLite-CSDN博客 如何生成静态库&#xff1a; 参考&#xff1a; WIN10 VS2019下编译GDAL3.0PROJ6SQLite_gdal 3 win10编译-CSDN博客 如何生成exe:…

电动车展示预约小程序的作用如何

电动车可以说是现在出行常见的方法&#xff0c;覆盖年龄广几乎是每家必备&#xff0c;也有不小大小品牌和经销商&#xff0c;市场需求较高&#xff0c;但在实际经营中&#xff0c;对经销商来时也面临着一些痛点&#xff1a; 1、品牌传播产品展示难 不同品牌竞争很大&#xff…

Spark 基础知识点

Spark 基础 本文来自 B站 黑马程序员 - Spark教程 &#xff1a;原地址 什么是Spark 什么是Spark 1.1 定义&#xff1a;Apache Spark是用于大规模数据&#xff08;large-scala data&#xff09;处理的统一&#xff08;unified&#xff09;分析引擎 Spark最早源于一篇论文 Re…

viple入门(五)

&#xff08;1&#xff09;自定义活动 自定义活动&#xff0c;用来创建新的组件、服务、函数或者其他代码模块&#xff0c;使用最多的是创建函数。 函数是对一个功能的封装&#xff0c;在调用的时候执行&#xff0c;没有调用的时候则不执行。函数可能有参数&#xff0c;可能没…

信号发送与处理-上

问题 按下 Ctrl C 后&#xff0c;命令行中的前台进程会被终止。为什么&#xff1f;&#xff1f;&#xff1f; 什么是信号&#xff1f; 信号是一种 "软件中断"&#xff0c;用来处理异步事件 内核发送信号到某个进程&#xff0c;通知进程事件的发送事件可能来自硬件…

基于 golang 从零到一实现时间轮算法 (三)

引言 本文参考小徐先生的相关博客整理&#xff0c;项目地址为&#xff1a; https://github.com/xiaoxuxiansheng/timewheel/blob/main/redis_time_wheel.go。主要是完善流程以及记录个人学习笔记。 分布式版实现 本章我们讨论一下&#xff0c;如何基于 redis 实现分布式版本的…

RuntimeError: Distributed package doesn‘t have NCCL built in

因为windows不支持NCCL backend 已解决 import os os.environ["PL_TORCH_DISTRIBUTED_BACKEND"] "gloo"

TextMate v2.0.23(文本编辑器)

Mac上好用的文本编辑器是哪个&#xff1f;TextMate 2 mac版是Macos上一款文本编辑器&#xff0c;支持大量编程语言并作为开源开发。该软件与“BBEdit”并成为苹果电脑上的EMACS和vim&#xff0c;对于程序员来说非常的适合&#xff0c;可以定制许多贴心的功能。为专业脚本编写者…