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

news2024/10/6 12:21:23

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
         */
        @Override
        public 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容器中注册一个bean
    	void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
    	throws BeanDefinitionStoreException;
    
    	// 该方法表明我们可以通过BeanDefinitionRegistry对象在Spring容器中移除一个bean
    	void 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
     */
    @Override
    public 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.coloradmin.cn/o/451916.html

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

相关文章

数据转换器的工程师指南

数据转换是连接模拟和数字世界的重要电路&#xff0c;在大多数嵌入式系统中&#xff0c;您都会发现模拟到数字转换和数字到模拟转换&#xff0c;从物联网&#xff08;IoT&#xff09;传感器到无线网络&#xff0c;从智能家居自动化到电源&#xff0c;数据转换无处不在。在本文中…

Git在工作中的使用流程

Git中的分支 master分支&#xff1a;所有用户可见的正式版本&#xff0c;都从master发布&#xff08;也是用于部署生产环境的分支&#xff0c;确保master分支稳定性&#xff09;。主分支作为稳定的唯一代码库&#xff0c;不做任何开发使用。master 分支一般由develop以及hotfi…

自学黑客/网络安全,三个月究竟能学到多少知识?

现在可以看到很多标题都是三个月零基础转行网络安全&#xff0c;三个月成为网络安全工程师月入15K&#xff0c;还有很多一系列类似吸引人的标题&#xff0c;那这些话是不是真实情况呢&#xff1f;那我们就来整理一下这三个月可以学到什么&#xff0c;然后再来看根据三个月的学习…

PyTorch训练提升

1. 更换学习率schedule 学习率 schedule 的选择对模型的收敛速度和泛化能力有很大的影响。Leslie N. Smith 等人在论文《Cyclical Learning Rates for Training Neural Networks》、《Super-Convergence: Very Fast Training of Neural Networks Using Large Learning Rates 》…

web前端 --- CSS(1)

CSS&#xff08;Cascade Style Sheet&#xff09; --- 级联样式表&#xff08;1&#xff09; <head><style>选择器{属性名&#xff1a;属性值;属性名&#xff1a;属性值;}</style> </head>属性名&#xff1a;修饰对象的属性&#xff08;样式&#xff…

docker ——安装tomcat

环境&#xff1a;centos7 安装tomcat 第一步&#xff1a;联网 第二步&#xff1a;开启docker systemctl start docker 第三步&#xff1a;拉取镜像 docker pull tomcat //下载tomcat镜像 docker pull tomcat 第四步&#xff1a;创建容器 docker run -d …

Solr之查询页面,索引,SolrJ

文章目录 1 Solr查询1.1 查询页面1.1.1 基本查询1.1.2 Solr检索运算符1.1.3 高亮1.1.4 分组1.1.4.1 分组&#xff08;Field Facet&#xff09;1.1.4.2 分组&#xff08;Date Facet&#xff09; 1.2 创建索引文件1.2.1 使用Post上传文件1.2.1.1 Linux下使用1.2.1.1.1 索引XML1.2…

BDCC- 数据湖体系

文章目录 数据湖的概念数据湖 vs 数据仓库 vs Lakehouse① 业界进展&#xff08;Databricks 2.0&#xff09;-湖上建仓② 业界进展&#xff08;Snowflake EDW 2.0&#xff09;-仓外挂湖 LakeHouse 的演进&#xff08;1&#xff09;Lakehouse 的演进路线&#xff08;2&#xff0…

基于matlab的长短期神经网络LSTM的电力负荷预测

目录 背影 摘要 LSTM的基本定义 LSTM实现的步骤 基于长短期神经网络LSTM的电力负荷预测 MATALB代码 效果图 结果分析 展望 参考论文 背影 电力负荷预测的实质是从已知的电力系统&#xff0c;经济&#xff0c;社会&#xff0c;气象等情况出发&#xff0c;根据历史负荷变化规律…

CSDN 周赛 48 期

CSDN 周赛 48 期 工作日参赛1、题目名称&#xff1a;最后一位2、题目名称&#xff1a;天然气订单3、题目名称&#xff1a;排查网络故障4、题目名称&#xff1a;运输石油小结 工作日参赛 说实话&#xff0c;今天是周末&#xff0c;但是今天也是工作日&#xff0c;老顾已经预计到…

Tossim 教程

系列文章目录 TinyOS 系列文章【一】&#xff1a;TinyOS 配置教程 TinyOS 系列文章【二】&#xff1a;Tossim 教程 文章目录 系列文章目录前言1. Tossim 简介2. TOSSIM 仿真2.1. 编译 TOSSIM2.2. 基于 Python 的仿真2.3. 调试语句2.4. 网络配置 总结 前言 本文主要用于记录在…

打破广播电视行业前端摄录设备依赖进口局面,BOSMA博冠全新国产8K摄像机重新定义广播世界

《世界广播电视》杂志曾经预测&#xff0c;2025年全球将有1000个超高清频道在播出。中国广电总局提出&#xff0c;到2025年底&#xff0c;标清频道基本关停&#xff0c;省级电视台要基本具备超高清电视制播能力。视频超高清已成为一个国际趋势。中国有14亿人口&#xff0c;是全…

蓝牙设备节点协议栈基础知识

蓝牙设备节点协议栈基础知识 一&#xff1a;TTY&#xff08;虚拟控制台&#xff0c;串口以及伪终端设备组成的终端设备&#xff09; Android/Linux 几乎所有的外设都以”设备节点”的形式存在 例如PC插入串口,会识别成COM1/COM2…在linux下面则以/dev/ttyXXX的形式存在,如/dev…

国家信息安全水平考试中NISP一级网络安全证书介绍

1、什么是NISP? 国家信息安全水平考试&#xff08;National Information Security Test Program&#xff0c;简称NISP&#xff09;&#xff0c;是由中国信息安全测评中心实施培养国家网络空间安全人才的项目。 2、考取NISP一级认证的同学就业岗位和薪资标准有那些呢&#xf…

Docker创建镜像,建立网桥,容器制作虚拟机

新建基础镜像&#xff0c;希望能够SSH&#xff0c;安装java&#xff0c;用户&#xff0c;声明22端口等等&#xff1b;拷贝基础hadoop安装文件 新建Dockerfile FROM centos:7.9.2009RUN rm -f /etc/localtime && ln -sv /usr/share/zoneinfo/Asia/Shanghai /etc/local…

【C++】Windows使用Visual Studio C++链接云数据库PostgreSQL(沉浸式老爷教学)

Windows使用C Visual Studio链接云数据库PostgreSQL 一、前置条件二、安装PostgreSQL工具三、编译libpqxx库四、Visual Studio配置测试**如果对您有帮助&#xff0c;关注收藏&#xff01;** 关注 “测试开发自动化” 公众号&#xff0c;获取更多学习内容 一、前置条件 下载lib…

MQTT 开放基准测试规范:全面评估你的 MQTT Broker 性能

引言 我们很高兴地宣布&#xff1a;由 EMQ 提供的 MQTT 开放基准测试规范现已正式发布&#xff01; 该测试规范包含了实用的典型使用场景、一套衡量 Broker 性能的主要指标&#xff0c;以及一个模拟负载和收集测试结果的工具&#xff0c;可以帮助开发者评估 MQTT Broker 的可…

让同为2.4G的ZigBee与Wi-Fi相容的解决方案解析

2.4G (WIFI,BT,ZIGBEE,普通2.4G 无线) 4种2.4G 无线通信协议。 普通2.4G 无线 最便宜。 众所周知&#xff0c;小米的智能套装包含的4件套&#xff0c;人体传感器、门窗传感器、无线开关与多功能网关采用的是基于NXP的一颗工业级ZigBee射频芯片–JN5168进行组网通讯。而多功能网…

office实操技能01:修改微软Office页面的(非背景的)浅绿底色、设置默认字体和主题颜色、取消页眉横线、PPT默认的等线字体

目录 1 处理word中默认中文字体是等线的问题 2 处理word中没有设置背景色&#xff0c;但页面底色是浅绿色的问题 3 修改office的主题颜色 4 删除页眉横线 5 处理PPT中的等线字体 这篇博文主要介绍两个使用技能&#xff1a; 技能1&#xff1a;修改word的默认等线字体技能2&…

( “树” 之 BST) 653. 两数之和 IV - 输入二叉搜索树 ——【Leetcode每日一题】

二叉查找树&#xff08;BST&#xff09;&#xff1a;根节点大于等于左子树所有节点&#xff0c;小于等于右子树所有节点。 二叉查找树中序遍历有序。 653. 两数之和 IV - 输入二叉搜索树 难度&#xff1a;简单 给定一个二叉搜索树 root 和一个目标结果 k&#xff0c;如果二叉…