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

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存在指定项

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

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

相关文章

基于 Python 的 Meta AI —— SAM

Segment Anything Model&#xff08;SAM&#xff09;是 Facebook 的一个 AI 模型&#xff0c;旨在推广分割技术。在我们之前的文章中&#xff0c;我们讨论了 SAM 的一般信息&#xff0c;现在让我们深入了解其技术细节。SAM 模型的结构如下图所示&#xff0c;图像经过编码器得到…

Leetcode-day4【88】【167】【125】【345】

文章目录 88. 合并两个有序数组题目解题思路解题思路【学习】尾插入法 167. 两数之和 II - 输入有序数组题目解题思路 125. 验证回文串题目解题思路 345. 反转字符串中的元音字母题目解题思路 88. 合并两个有序数组 题目 给你两个按 非递减顺序 排列的整数数组 nums1 和 nums…

修改DaemonSet 的/args参数后多个pod重启的顺序

理论 当您修改了DaemonSet的/args参数时&#xff0c;DaemonSet控制器会自动触发Pod的滚动更新。滚动更新的过程是逐个将旧的Pod删除并创建新的Pod&#xff0c;以确保应用程序的高可用性和稳定性。 在进行滚动更新时&#xff0c;DaemonSet控制器会按照以下步骤逐个重启Pod&…

问卷中多选题如何分析?

一、案例与问卷 本研究选取大学生作为研究对象&#xff0c;旨在通过理财认知、理财现状、理财偏好三个方面&#xff0c;对大学生理财产品了解情况、使用需求进行调查。本次问卷共分为四个部分&#xff1a;第一部分共5道题&#xff0c;为基本信息题&#xff1b;第二部分共3道题…

【Linux高性能服务器编程】I/O复用的高级应用

文章目录 一、基于 select 的非阻塞 connect二、基于 poll 的聊天室程序2.1 客户端2.2 服务器 三、基于 epoll 实现同时处理 TCP 和 UDP 服务 一、基于 select 的非阻塞 connect connect系统调用的 man 手册中有如下一段内容&#xff1a; EINPROGERESS The socket is nonblock…

结构型模式-适配器模式

适配器模式 概述 如果去欧洲国家去旅游的话&#xff0c;他们的插座如下图最左边&#xff0c;是欧洲标准。而我们使用的插头如下图最右边的。因此我们的笔记本电脑&#xff0c;手机在当地不能直接充电。所以就需要一个插座转换器&#xff0c;转换器第1面插入当地的插座&#x…

【java笔记】java多线程

目录 一、概念 1.1 什么是进程&#xff1f; 1.2 什么是线程&#xff1f; 1.3 什么事多线程&#xff1f; 1.4 进程和线程的关系 二、线程对象的生命周期 三、实现线程有两种方式 3.1 继承 java.lang.Thread&#xff0c;重写 run方法 3.2 实现 java.lang.Runnable 接口…

图像描述算法排位赛:SceneXplain 与 MiniGPT4 谁将夺得桂冠?

如果你对图像描述算法的未来感到好奇&#xff0c;本场“图像描述算法排位赛”绝对是你不能错过的&#xff01;在这场较量中&#xff0c;SceneXplain 和 MiniGPT-4 将会比试&#xff0c;谁将摘得这场比赛的桂冠&#xff1f; 背景介绍 在上篇文章中&#xff0c;我们介绍了图像描述…

【UE】倒计时归零时结束游戏

上一篇博客&#xff08;【UE】一个简易的游戏计时器&#xff09;完成了游戏时间每秒1的功能&#xff0c;本篇博客在此基础上完成倒计归零时结束游戏的功能 效果 步骤 1. 打开“ThirdPersonGameMode”&#xff0c;将剩余的秒数和分钟数的默认值分别设置为1和59 在事件图表中添…

Java设计模式-day02

4&#xff0c;创建型模式 4.2 工厂模式 4.2.1 概述 需求&#xff1a;设计一个咖啡店点餐系统。 设计一个咖啡类&#xff08;Coffee&#xff09;&#xff0c;并定义其两个子类&#xff08;美式咖啡【AmericanCoffee】和拿铁咖啡【LatteCoffee】&#xff09;&#xff1b;再设…

Linux: 进程间通信机制

文章目录 1. 前言2. 进程间通信机制2.1 管道2.1.1 匿名管道2.1.2 popen() 和 pclose()2.1.3 命名管道 FIFO 2.2 消息队列2.3 共享内存2.4 信号量2.5 网络套接字2.6 UNIX套接字2.7 信号 3. 参考资料 1. 前言 限于作者能力水平&#xff0c;本文可能存在谬误&#xff0c;因此而给…

Javaee Spring的AOP简介

一.Spring的AOP简介 1.1 什么是AOP AOP 为 Aspect Oriented Programming 的缩写&#xff0c;意思为面向切面编程&#xff0c;是通过预编译方式和运行期动态代 理实现程序功能的统一维护的一种技术。AOP 是 OOP 的延续&#xff0c;是软件开发中的一个热点&#xff0c;也是…

shell脚本控制

shell脚本编程系列 处理信号 Linux利用信号与系统中的进程进行通信&#xff0c;通过对脚本进行编程&#xff0c;使其在收到特定信号时执行某些命令&#xff0c;从而控制shell脚本的操作。 Linux信号 shell脚本编程会遇到的最常见的Linux系统信号如下表所示&#xff1a; 在默…

【获奖案例巡展】信创先锋之星——浙江省某市区视频能力中心

为表彰使用大数据、人工智能等基础软件为企业、行业或世界做出杰出贡献和巨大创新的标杆项目&#xff0c;星环科技自2021年推出了“新科技 星力量” 星环科技科技实践案例评选活动&#xff0c;旨在为各行业提供更多的优秀产品案例&#xff0c;彰显技术改变世界的力量&#xff0…

Cycling 74 Max for Mac:音乐可视化编程软件

Cycling 74 Max是一款音乐、视觉、互动艺术等领域中广泛使用的编程语言和应用软件&#xff0c;它允许用户创作和控制实时音频和视频效果、交互式应用程序和媒体艺术品等。 Max将程序设计和可视化编程相结合&#xff0c;通过简单的拖拽和连接方式&#xff0c;用户可以将各种功能…

基于springboot的大学生租房系统源码论文数据库

3.1系统功能 现在无论是在PC上还是在手机上&#xff0c;相信全国所有地方都在进行大学生租房管理。随着经济的不断发展&#xff0c;系统管理也在不断增多&#xff0c;大学生租房系统就是其中一种&#xff0c;很多人会登录到相关的租房系统查看租房信息&#xff0c;还能查看房屋…

微信小程序开发--利用和风天气API实现天气预报小程序

本来是参照《微信小程序开发实战》做一个天气预报小程序的&#xff0c;实际运行的时候提示错误&#xff0c;code 400&#xff0c;参数错误。说明问题应该出在查询API的语句上&#xff0c;没有返回结果。 查阅后才知道&#xff0c;可能书籍出版时间较早&#xff0c;现在的和风获…

类对象

一、类初识 类&#xff1a;表示一种事物所具有的共同特征和行为 对象&#xff1a;一个类的实例 如下图&#xff0c;通过狗这个类进行详解 这是一个Dog类 对象&#xff1a;斗牛犬、小猎犬、牧羊犬 类中的属性&#xff1a;breed(品种)、size(大小)、color(颜色)、age(年龄)、 …

安全常见基础名词概念

一、域名 1、域名&#xff1a;相当网站的名字&#xff0c;互联网上某一台计算机或计算机组的名称&#xff0c;用于在数据传输时标识计算机的电子方位。 2、网域名系统&#xff08;Domain Name System&#xff09;有时也简称为域名&#xff08;DNS&#xff09;&#xff0c;是互…

探索【Stable-Diffusion WEBUI】的插件:骨骼姿态(OpenPose)

文章目录 &#xff08;零&#xff09;前言&#xff08;一&#xff09;骨骼姿态&#xff08;OpenPose&#xff09;系列插件&#xff08;二&#xff09;插件&#xff1a;PoseX&#xff08;三&#xff09;插件&#xff1a;Depth Lib&#xff08;四&#xff09;插件&#xff1a;3D …