按照条件向Spring容器中注册bean

news/2024/5/4 1:19:47/文章来源:https://blog.csdn.net/weixin_44230693/article/details/130322566

1.@Conditional注解概述

@Conditional注解可以按照一定的条件进行判断,满足条件向容器中注册bean,不满足条件就不向容器中注册bean。

package org.springframework.context.annotation;import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {/*** All {@link Condition} classes that must {@linkplain Condition#matches match}* in order for the component to be registered.*/Class<? extends Condition>[] value();
}

@Conditional注解不仅可以添加到类上,也可以添加到方法上。

@Conditional注解中,还存在着一个Condition类型或者其子类型的Class对象数组。

package org.springframework.context.annotation;import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.core.type.AnnotatedTypeMetadata;@FunctionalInterface
public interface Condition {boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
}

是一个接口,所以在使用@Conditional注解时,需要写一个类来实现Spring提供的Condition接口,它会匹配@Conditional所符合的方法,然后就可以使用在@Conditional注解中定义的类来检查了。

在这里插入图片描述

2.向Spring容器注册bean

2.1.不带条件注册bean

package com.tianxia.springannotation.config;import com.tianxia.springannotation.entity.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;/*** 配置类* @author liqb* @date 2023-04-23 9:45**/
@Configuration
public class MainConfig02 {/*** 创建person实例* @author liqb* @date 2023-04-23 09:46* @return*/@Bean("person02")//通过@Scope注解来指定该bean的作用范围,也可以说成是调整作用域@Scope("prototype")public Person person() {System.out.println("给容器中添加咱们这个Person对象...");return new Person("liqb", 24);}/*** 创建person实例 名为bill* @author liqb* @date 2023-04-23 12:47* @return*/@Bean("bill")public Person person01() {return new Person("Bill Gates", 62);}/*** 创建person实例 名为linus* @author liqb* @date 2023-04-23 12:47* @return*/@Bean("linus")public Person person02() {return new Person("linus", 48);}
}

测试两个bean是否被注册到Spring容器中

/*** 测试bill,linus是否被注入到spring中* @author liqb* @date 2023-04-23 12:50*/
@Test
public void test06() {AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig02.class);// 查看IOC容器中Person这种类型的bean都有哪些String[] namesForType = applicationContext.getBeanNamesForType(Person.class);for (String name : namesForType) {System.out.println(name);}
}

输出的结果信息如下所示:

在这里插入图片描述

结论:说明默认情况下,Spring容器会将单实例并且非懒加载的bean注册到IOC容器中。

2.2.带条件注册bean

需求:比如,如果当前操作系统是Windows操作系统,那么就向Spring容器中注册名称为bill的Person对象;如果当前操作系统是Linux操作系

统,那么就向Spring容器中注册名称为linus的Person对象。要想实现这个需求,我们就得要使用@Conditional注解了。

  • LinuxCondition

    package com.tianxia.springannotation.config.configCondition;import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
    import org.springframework.beans.factory.support.BeanDefinitionRegistry;
    import org.springframework.context.annotation.Condition;
    import org.springframework.context.annotation.ConditionContext;
    import org.springframework.core.env.Environment;
    import org.springframework.core.type.AnnotatedTypeMetadata;/*** 判断操作系统是否是Linux系统* @author liqb* @date 2023-04-23 12:56**/
    public class LinuxCondition implements Condition{/*** 匹配方法* @author liqb* @date 2023-04-23 12:57* @param context 判断条件能使用的上下文(环境)* @param metadata 当前标注了@Conditional注解的注释信息* @return*/@Overridepublic boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {// 判断操作系统是否是Linux系统// 1. 获取到bean的创建工厂(能获取到IOC容器使用到的BeanFactory,它就是创建对象以及进行装配的工厂)ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();// 2. 获取到类加载器ClassLoader classLoader = context.getClassLoader();// 3. 获取当前环境信息,它里面就封装了我们这个当前运行时的一些信息,包括环境变量,以及包括虚拟机的一些变量Environment environment = context.getEnvironment();// 4. 获取到bean定义的注册类BeanDefinitionRegistry registry = context.getRegistry();// 在这儿还可以做更多的判断,比如说我判断一下Spring容器中是不是包含有某一个bean,就像下面这样,如果Spring容器中果真包含有名称为person的bean,那么就做些什么事情...boolean definition = registry.containsBeanDefinition("person");String property = environment.getProperty("os.name");if (property.contains("linux")) {return true;}return false;}
    }

    理解:通过context的getRegistry()方法获取到的bean定义的注册对象,即BeanDefinitionRegistry对象。

    如下所示,可以看到它是一个接口

    package org.springframework.beans.factory.support;import org.springframework.beans.factory.BeanDefinitionStoreException;
    import org.springframework.beans.factory.NoSuchBeanDefinitionException;
    import org.springframework.beans.factory.config.BeanDefinition;
    import org.springframework.core.AliasRegistry;// spring容器中所有的bean都是通过BeanDefinitionRegistry对象来进行注册的
    // 因此我们可以通过它来查看Spring容器中注册了哪些bean
    public interface BeanDefinitionRegistry extends AliasRegistry {// 该方法表明我们可以通过BeanDefinitionRegistry对象向5pring容器中注册一个beanvoid registerBeanDefinition(String beanName, BeanDefinition beanDefinition)throws BeanDefinitionStoreException;// 该方法表明我们可以通过BeanDefinitionRegistry对象在Spring容器中移除一个beanvoid removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;// 该方法表明我们可以通过BeanDefinitionRegistry对象查看某个bean的定义信息BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;// 该方法表明我们可以通过BeanDefinitionRegistry对象查看对象Spring// 容器中是否包含某一个bean的定义boolean containsBeanDefinition(String beanName);String[] getBeanDefinitionNames();int getBeanDefinitionCount();boolean isBeanNameInUse(String beanName);
    }
    

    可以通过BeanDefinitionRegistry对象向Spring容器中注册一个bean、移除一个bean、查询某一个bean的定义信息或者判断Spring容器

    中是否包含有某一个bean的定义。

  • WindowsCondition

package com.tianxia.springannotation.config.configCondition;import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;/*** 判断操作系统是否是Linux系统* @author liqb* @date 2023-04-23 14:40**/
public class WindowsCondition implements Condition {/*** 匹配方法* @author liqb* @date 2023-04-23 12:57* @param context 判断条件能使用的上下文(环境)* @param metadata 当前标注了@Conditional注解的注释信息* @return*/@Overridepublic boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {Environment environment = context.getEnvironment();String property = environment.getProperty("os.name");if (property.contains("Windows")) {return true;}return false;}
}

配置类中使用@Conditional注解添加条件,添加该注解后的方法如下所示。

package com.tianxia.springannotation.config;import com.tianxia.springannotation.config.configCondition.LinuxCondition;
import com.tianxia.springannotation.config.configCondition.WindowsCondition;
import com.tianxia.springannotation.entity.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;/*** 配置类* @author liqb* @date 2023-04-23 9:45**/
@Configuration
public class MainConfig02 {/*** 创建person实例* @author liqb* @date 2023-04-23 09:46* @return*/@Bean("person02")//通过@Scope注解来指定该bean的作用范围,也可以说成是调整作用域@Scope("prototype")public Person person() {System.out.println("给容器中添加咱们这个Person对象...");return new Person("liqb", 24);}/*** 创建person实例 名为bill* @author liqb* @date 2023-04-23 12:47* @return*/@Bean("bill")@Conditional({WindowsCondition.class})public Person person01() {return new Person("Bill Gates", 62);}/*** 创建person实例 名为linus* @author liqb* @date 2023-04-23 12:47* @return*/@Bean("linus")@Conditional({LinuxCondition.class})public Person person02() {return new Person("linus", 48);}
}

在运行测试方法,输出的结果信息如下所示:

在这里插入图片描述

输出结果中不再含有名称为linus的bean了,这说明程序中检测到当前操作系统为Windows 10之后,没有向Spring容器中注册名称为linus的bean。

@Conditional注解也可以标注在类上,标注在类上的含义是:只有满足了当前条件,这个配置类中配置的所有bean注册才能生效,也就是对配置类中的组件进行统一设置。

package com.tianxia.springannotation.config;import com.tianxia.springannotation.config.configCondition.LinuxCondition;
import com.tianxia.springannotation.config.configCondition.WindowsCondition;
import com.tianxia.springannotation.entity.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;/*** 配置类* @author liqb* @date 2023-04-23 9:45**/
@Configuration
// 满足当前条件,这个类中配置的所有bean注册才能生效
@Conditional({LinuxCondition.class}) 
public class MainConfig02 {/*** 创建person实例* @author liqb* @date 2023-04-23 09:46* @return*/@Bean("person02")//通过@Scope注解来指定该bean的作用范围,也可以说成是调整作用域@Scope("prototype")public Person person() {System.out.println("给容器中添加咱们这个Person对象...");return new Person("liqb", 24);}/*** 创建person实例 名为bill* @author liqb* @date 2023-04-23 12:47* @return*/@Bean("bill")@Conditional({WindowsCondition.class})public Person person01() {return new Person("Bill Gates", 62);}/*** 创建person实例 名为linus* @author liqb* @date 2023-04-23 12:47* @return*/@Bean("linus")@Conditional({LinuxCondition.class})public Person person02() {return new Person("linus", 48);}
}

运行测试方法之后,发现输出的结果信息如下所示:

在这里插入图片描述

没有任何bean的定义信息输出,这是因为程序检测到了当前操作系统为window,没有向Spring容器中注册任何bean的缘故导致的。

3.@Conditional的扩展注解

@Conditional扩展注解作用 (判断是否满足当前指定条件)
@ConditionOnJava系统的Java版本是否符合要求
@ConditionOnBean容器中存在指定Bean
@ConditionOnMissingBean容器中不存在指定Bean
@ConditionOnExpression满足SpEL表达式指定
@ConditionOnClass系统中有指定的类
@ConditionOnMissingClass系统中没有指定的类
@ConditionOnSingleCandidate容器中只有一个指定的bean,或者这个bean是首选bean
@ConditionOnProperty系统中指定的属性是否有指定的值
@ConditionOnResource类路径下是否存在指定资源文件
@ConditionalOnWebApplication当前是web环境
@ConditionalOnNoWebApplication当前不是web环境
@ConditionalOnJndiJNDI存在指定项

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

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

相关文章

9. 树的进阶

9. 树的进阶 ​ 之前我们学习过二叉查找树&#xff0c;发现它的查询效率比单纯的链表和数组的查询效率要高很多&#xff0c;大部分情况下&#xff0c;确实是这样的&#xff0c;但不幸的是&#xff0c;在最坏情况下&#xff0c;二叉查找树的性能还是很糟糕。 例如我们依次往二叉…

RelativeLayout相对布局

一、官方地址&#xff1a; https://developer.android.google.cn/reference/kotlin/android/widget/RelativeLayout?hlen 二、概述 相对布局&#xff08;RelativeLayout&#xff09;是一种根据父容器和兄弟控件作为参照来确定控件位置的布局方式 三、基本格式 <RelativeLay…

Jenkins配置邮箱发送报告

本文以qq邮箱为例 1.下载Email Extension Plugin插件 2.在Manage Jenkins--System&#xff0c;Jenkins Location下配置理员邮件 Extended E-mail Notification 下配置Jenkins SMTP server&#xff08;邮箱服务&#xff09;、SMTP Port&#xff08;邮箱端口&#xff09;、Cred…

无法解析的外部符号 __mingw_vsprintf

windows下的ffmpeg是采取mingw平台上编译&#xff0c;本人采用的是msys2&#xff0c;本人需要h264&#xff0c;于是先在msys2里面编译了x264静态库&#xff0c;注意这里是静态库&#xff0c;动态库经过了链接&#xff0c;不会出现下面的问题&#xff0c;然后在ffmpeg里面用下面…

Java项目打包exe运行文件

Java项目打包exe运行文件 JavaSE打包成exe运行文件的方法有很多种&#xff0c;此处我们主要讲解我常用的一种exe4j&#xff0c;打包前我们需要先安装exe4j这个工具。 注意&#xff1a;exe4j仅支持最低JDK1.8最高JDK11&#xff0c;所以在安装之前一定要查看自己的JDK版本&#…

【移动端网页布局】移动端网页布局基础概念 ⑤ ( 视网膜屏技术 | 二倍图概念 | 代码示例 )

文章目录 一、视网膜屏技术二、二倍图概念三、代码示例 一、视网膜屏技术 PC 端 和 早期的 移动端 网页中 , CSS 中配置的 1 像素 对应的就是物理屏幕中的 1 像素 ; Retina 视网膜屏幕 技术出现后 , 将多个物理像素压缩到一块屏幕中 , 可以达到更高的分辨率 , 画面显示效果更好…

C/C++笔记-写一个Makefile并链接QtCore库使用QString,QDebug

如下cpp代码&#xff0c;调用QDebug打印程序&#xff1a; #include <QDebug> #include <QString>int main(int argc, char *argv[]){QString testStr "hello";qDebug() << testStr;return 0; } 如下makefile&#xff1a; test: main.cppg -c -…

自编码器简单介绍—使用PyTorch库实现一个简单的自编码器,并使用MNIST数据集进行训练和测试

文章目录 自编码器简单介绍什么是自编码器&#xff1f;自动编码器和卷积神经网络的区别&#xff1f;如何构建一个自编码器&#xff1f;如何训练自编码器&#xff1f;如何使用自编码器进行图像压缩&#xff1f;总结使用PyTorch构建简单的自动编码器第一步&#xff1a;导入库和数…

【JavaEE】社区版IDEA(2021.X版本及之前)创建SpringBoot项目

目录 下载Spring Boot Helper 创建项目 下载相关依赖 判断成功 删除多余文件 项目建好后添加依赖 输出Hello World SpringBoot的优点 下载Spring Boot Helper 创建项目 下载相关依赖 如果没有配置过国内源&#xff0c;参考【JavaEE】Spring项目的创建与使用_p_fly的博…

M_Map工具箱简介及地理图形绘制

M_Map工具箱简介及地理图形绘制 1 M_Map简介1.1 具体代码说明 2 地理图形绘制案例2.1 M_Map给定案例2.1.1 M_Map Logo2.1.2 Lambert Conformal Conic projection of North American Topography2.1.3 Stereographic projection of North Polar regions2.1.4 Colourmaps 2.2 案例…

【社区图书馆】 Go佬—Go程序开发实战宝典书评

文章目录 前言内容介绍文章大致划分总结 前言 《Go 程序开发实战宝典》是一本非常实用的 Go 语言开发工具书&#xff0c;本书由深入浅出的案例讲解、详细的技术实现、贴近实际的应用开发等组成&#xff0c;非常适合 Go 语言开发爱好者、从事相关行业的工程师、技术负责人以及深…

Spring依赖注入的三种方式使用及优缺点

初学Spring的时候,我们从Spring容器中获取Bean对象都是通过bean标签先将Bean对象注册到Spring容器中&#xff0c;然后通过上下文对象congtext的getBean方法进行获取&#xff0c;显然这种方法较为麻烦&#xff0c;所以有了更简单的存方法&#xff1a;五大类注解&#xff1b;取方…

Elasticsearch:了解和解决文档更新后 Elasticsearch 分数的变化

问题 问卷中有如下这样的文档&#xff0c;开发者想通过 match query 搜索这些文档来使用分数。 POST sample-index-test/_doc/1 {"first_name": "James","last_name" : "Osaka" } 以下是对上述文档的示例查询&#xff1a; GET sam…

贾其萃 : 笃行实践 筑梦扬帆 | 提升之路系列(二)

导读 为了发挥清华大学多学科优势&#xff0c;搭建跨学科交叉融合平台&#xff0c;创新跨学科交叉培养模式&#xff0c;培养具有大数据思维和应用创新的“π”型人才&#xff0c;由清华大学研究生院、清华大学大数据研究中心及相关院系共同设计组织的“清华大学大数据能力提升项…

LeetCode特训 --- Week2 (主打滑动窗口 + 字符串匹配题目)

目录 滑动窗口原理 真懂了滑动窗口? 滑动 字符串细节 开干切题 滑动窗口原理 滑动窗口&#xff1a;维护一前一后两根指针, 或者说一左一右两个指针。更主要的是维护左右指针中的区间. 同时不断的向前滑动&#xff0c;直到整个序列滑动结束&#xff0c;前指针走到序列末尾…

有什么好用的远程工具吗

沟通在任何类型的工作中都扮演着重要的角色。但当谈到远程工作时&#xff0c;这一点就更为重要。因此&#xff0c;您的组织必须找到可以让您的团队保持一致的工具。 在某些方面&#xff0c;项目管理扮演着类似的角色。 您会注意到&#xff0c;下面的大多数工具都会直接影响您的…

Java核心技术 卷1-总结-10

Java核心技术 卷1-总结-10 通配符类型通配符概念通配符的超类型限定无限定通配符通配符捕获 通配符类型 通配符概念 通配符类型中&#xff0c;允许类型参数变化。 例如&#xff0c;通配符类型Pair<? extends Employee>表示任何泛型Pair类型&#xff0c;它的类型参数是…

【Linux】uptime命令详解平均负载

命令 ➜ ~ uptime 22:37 up 90 days, 21:45, 2 users, load averages: 2.91 3.46 3.81 具体含义 22:37&#xff1a;代表的是当前的系统时间&#xff0c;也即晚上10点37分。 up 90 days, 21:45&#xff1a;代表系统运行时间 2 users &#xff1a;当前两个用户 load averages: 2…

ChatGPT实战100例 - (06) 10倍速可视化组织架构与人员协作流程

文章目录 ChatGPT实战100例 - (06) 10倍速可视化组织架构与人员协作流程一、需求与思路二、 组织架构二、 人员协作四、 总结 ChatGPT实战100例 - (06) 10倍速可视化组织架构与人员协作流程 一、需求与思路 管理研发团队的过程中&#xff0c;组织架构与人员协作流程的可视化是…

知识变现海哥|你为什么知识却不富有,是你不懂这个道理

要有价值观念&#xff0c;要有交换思维。商业的本质都是基于价值交换&#xff0c;你能为别人提供多少价值&#xff0c;你就能赚多少米&#xff0c;你帮助别人处理的问题越多你越有价值&#xff0c;你能成就多少人你就能被多少人成就。这是商业行为的底层逻辑。 你没赚到米 一是…