【SpringBoot_ANNOTATIONS】组件注册 06 @Conditional 按照条件注册bean

SpringBoot底层大量使用的注解,表示按照一定的条件进行判断,若满足条件则给容器中注册bean
@Conditional可以标注在类上 也可以标注在方法上

    @Test
    void conditionTest(){
        //配置类测试
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
        System.out.println("容器创建完毕");
        System.out.println("准备获取bean...");
        Map<String, Person> beansOfType = applicationContext.getBeansOfType(Person.class);
        for (String person:beansOfType.keySet()){
            System.out.println(beansOfType.get(person));
        }
    }

MainConfig2.java

@Configuration
public class MainConfig2 {
    // 由于容器中已经有了一个名为"person"的bean, 所以如果再注入"person"的时候会报错 需要修改下注入的bean的名称

//    @Scope("prototype")
    @Bean("person2")
    public Person person(){
        System.out.println("person2创建中...");
        return new Person("qd2",22);
    }

    @Bean("bill")
    public Person person1(){
        System.out.println("bill创建中...");
        return new Person("bill",62);
    }

    @Bean("linus")
    public Person person2(){
        System.out.println("linus创建中...");
        return new Person("linus",48);
    }
}

在这里插入图片描述

加上条件判断

LinuxCondition.java

package com.example.annotations.condition;

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;

public class LinuxCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        // 获取IOC使用的beanFactory
        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
        // 获取类加载器
        ClassLoader classLoader = context.getClassLoader();
        // 获取bean定义的注册类
        BeanDefinitionRegistry registry = context.getRegistry();

        // 获取当前环境信息
        Environment environment = context.getEnvironment();
        // 动态获取环境变量的值
        String property = environment.getProperty("os.name");

        if (property.contains("Linux")){
            System.out.println("the running environment is 'Linux'");
            return true;
        }
        return false;
    }
}

注意

  1. 实现Condition接口的时候注意导的包
  2. 需要实现的方法:matches 参数解释:
    1. ConditionContext:判断条件能使用的上下文环境
  3. AnnotationTypeMetadata:注释信息
  4. BeanDefinitionRegistry registry = context.getRegistry(); 所有bean定义都在这个类,也可以用其来注册/移除/查询/一个bean定义

WindowsCondition.class

package com.example.annotations.condition;

import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;

public class WindowsCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        // 获取运行时环境
        Environment environment = context.getEnvironment();
        // 动态获取环境变量的值
        String property = environment.getProperty("os.name");
        // 匹配环境
        if (property.contains("Windows")){
            System.out.println("the running environment is 'Windows'");
            return true;
        }
        return false;
    }
}
@Configuration
public class MainConfig2 {
    // 由于容器中已经有了一个名为"person"的bean, 所以如果再注入"person"的时候会报错 需要修改下注入的bean的名称
    @Bean("person2")
    public Person person(){
        System.out.println("person2创建中...");
        return new Person("qd2",22);
    }

    @Conditional(WindowsCondition.class)
    @Bean("bill")
    public Person person1(){
        System.out.println("bill创建中...");
        return new Person("bill",62);
    }

    @Conditional(LinuxCondition.class)
    @Bean("linus")
    public Person person2(){
        System.out.println("linus创建中...");
        return new Person("linus",48);
    }
}

运行结果;
在这里插入图片描述

组建注册 @Import 给容器快速导入一个组件

给容器注册组件:

  1. 包扫描 + 组件标注注解(@Controller @Service @Repository @Component),局限于自己写的
  2. @Bean(可导入第三方包里的组件)
  3. @Import(快速给容器中导入组件)
    1. @Import([要导入容器中的组件]):容器中就会自动注册这个组件,id默认为全类名 @Import(Color.class) @Import({Color.class,Red.class})
    2. 实现ImportSelector接口:返回需要导入的组件的全类名数组
    3. 实现ImportBeanDefinitionRegistrar接口:手动注册bean到容器中
  4. 使用Spring提供的FactoryBean工厂

配置类 MainConfig3.class

测试

    @Test
    void importTest(){
        //配置类测试
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig3.class);
        System.out.println("容器创建完毕");
        System.out.println("准备获取bean...");
        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
        for (String name:beanDefinitionNames){
            System.out.println(name);
        }
    }

ImportSelector 测试

Color.java

package com.example.annotations.bean;

public class Color {
}

Red.java

package com.example.annotations.bean;

public class Red {
}

MyImportSelector.java

package com.example.annotations.importselector;

import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;

/**
 * 自定义逻辑返回需要导入的组件
 */
public class MyImportSelector implements ImportSelector {

    // 返回值:导入到容器中的组件 (全类名)
    // AnnotationMetadata:当前标注@Import注解的类的所有注解信息
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        // 不能返回 null  可以是空数组
        return new String[]{"com.example.annotations.bean.Color","com.example.annotations.bean.Red"};
    }
}

运行结果:
在这里插入图片描述

实现ImportBeanDefinitionRegistrar接口

MyImportBeanDefinitionRegistrar.class

package com.example.annotations.importselector;

import com.example.annotations.bean.RainBow;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;

public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

    /**
     *
     * @param importingClassMetadata 当前类的注解信息
     * @param registry               BeanDefinition的注册类  负责将bean添加进容器
     */
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        // 指定bean定义信息(Bean的类型 Bean的作用域 ...)
        RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(RainBow.class);

        // 注册:指定bean名
        if (!registry.containsBeanDefinition("rainbow")){
            System.out.println(" start create 'rainbow' ...");

            registry.registerBeanDefinition("rainbow",rootBeanDefinition);
        }else {
            System.out.println("'rainbow' already exists ");
        }
    }
}

运行结果
在这里插入图片描述

使用FatoryBean

普通bean

将bean导入到容器后,容器会调用其无参构造器,默认创建一个对象注册在容器中

FactoryBean

  1. 是一个接口
  2. 整合第三方框架的时候用的多
  3. 默认获取的是工厂bean调用getObject创建的对象
  4. 要获取工厂bean本身,需要给id前加一个 &
需要实现方法

getObject()
getObjectType()

isSingleton() :默认是true 单实例

实例测试

ColorFactoryBean.java

package com.example.annotations.bean;

import org.springframework.beans.factory.FactoryBean;

/**
 * 创建一个Spring定义的FactoryBean
 */
public class ColorFactoryBean implements FactoryBean<Color> {


    /**
     * 返回分Color对象会被添加到容器中
     * @return Color
     * @throws Exception
     */
    @Override
    public Color getObject() throws Exception {
        return new Color();
    }

    /**
     *
     * @return
     */
    @Override
    public Class<?> getObjectType() {
        return Color.class;
    }

    /**
     * true: 单实例 在容器中保存一份
     * false:多实例 每获取一次就会创建一个新bean
     * @return
     */
    @Override
    public boolean isSingleton() {
        return true;
    }
}

MainConfig2.java

@Configuration
public class MainConfig2 {
    @Bean
    public ColorFactoryBean colorFactoryBean(){
        return new ColorFactoryBean();
    }
}

测试

    @Test
    void factoryBeanTest(){
        //配置类测试
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
        System.out.println("容器创建完毕");
        System.out.println("准备获取bean...");
        Object bean1 = applicationContext.getBean("colorFactoryBean");//Color.class
        Object bean2 = applicationContext.getBean("colorFactoryBean");//Color.class
        System.out.println("bean1 == bean2? => " + (bean1 == bean2));
    }

测试结果
true 运行结果
现将ColorFactoryBean.java中的isSingleton改为false,再次运行
false 运行结果
查看获取的类型

    @Test
    void factoryBeanTest(){
        //配置类测试
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
        System.out.println("容器创建完毕");
        System.out.println("准备获取bean...");
        Object bean1 = applicationContext.getBean("colorFactoryBean");//Color.class  获取的是工厂bean调用 
        Object bean2 = applicationContext.getBean("&colorFactoryBean");//ColorFactoryBean.class
        System.out.println("bean1 == bean2? => " + (bean1 == bean2));
        System.out.println("bean1 " + bean1.getClass());
        System.out.println("bean2 " + bean2.getClass());
    }

类型测试

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值