spring5学习系列之------3 给容器注册组件三 @Conditional 和 @Import 注解用法

     前文主要介绍了@bean  @ComponentScan 扫包注入两种方式,今天介绍一下@Conditional按照条件注入和@import导入组件的相关用法

1 首先是@Conditional的用法:按照一定的条件进行判断,满足条件给容器中注册bean,之前是写了@bean注解就会注入,但是在bean上加了@Conditional注解,并不一定就会注入了,而是进行条件判断之后再说,该注解在springboot源码中大量用到,该注解是在spring4.0引入的。

  首先我们创建一个Config,并且在里面注册2个person的Bean其中一个为windows另外一个为linux,使用@Conditional注解来判断当前操作系统是windows还是linux分别加载不同的bean,见下图:

package com.study.chap4.conditional.config;
import com.study.chap4.conditional.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
@Conditional(WindowsCondition.class)
@Configuration
public class Config {
    /**
     * @Conditional({Condition}) : 按照一定的条件进行判断,满足条件给容器中注册bean
     *
     * 如果系统是windows,给容器中注册("windows")
     * 如果是linux系统,给容器中注册("linux")
     */
    @Bean("windows")
    public Person person01(){
        return new Person("windows",18,"我是windows系统");
    }
    @Conditional(LinuxCondition.class)
    @Bean("linux")
    public Person person02(){
        return new Person("linux", 48,"我是linux系统");
    }
}

  我们看下@Conditional源码可知,该注解可以用在类上和用在方法上,我们分别创建判断的条件类WindowsCondition,linuxCondition,这里为了节约空间,就只贴出一个类的代码

package com.study.chap4.conditional.config;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;
/**
 *  判断是否是windows系统
 *
 * */
public class WindowsCondition implements Condition {

    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        Environment environment = context.getEnvironment();
        String property = environment.getProperty("os.name");
        return property.contains("Windows");
    }
}

 然后再测试类上面输出所有注入的bean,由于系统运行是windows环境,所以windows的bean被注入,而linux没有

import com.study.chap4.conditional.config.Config;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class MainTest4 {
    @Test
    public void demoChap3(){
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(Config.class);
        String[] names = applicationContext.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }

    }
}

  2  使用@import注解快速给容器导入一个组件,观察import源码可知,该注解在spring3.0就有了,并且还可以link# ImportSelector:返回需要导入的组件的全类名数组;以及 ImportBeanDefinitionRegistrar:手动注册bean到容器中

因此,我们首先直接用import的用法,直接导入组件名

package com.study.chap4.imports;
import com.study.chap4.imports.pojo.Blue;
import com.study.chap4.imports.pojo.Red;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@Configuration
@Import({Red.class, Blue.class})
//@Import导入组件,默认是组件名是全类名
public class Config {
}

   输出可见

   

   再用一种方式,ImportSelector:返回需要导入的组件的全类名数组,并且再springboot的启动类中有用到这个特性,新建一个MyImportSelector去实现 ImportSelector 接口。

package com.study.chap4.imports;
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;
public class MyImportSelector implements ImportSelector {
    /**
     * @param importingClassMetadata  当前标注@Import注解的类的所有注解信息
     * @return 返回值,就是到导入到容器中的组件全类名
     */
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[]{"com.study.chap4.imports.pojo.Yellow"};
    }
}

   再使用第三种方式  ImportBeanDefinitionRegistrar:手动注册bean到容器中,ImportBeanDefinitionRegistrar在springboot启动类中也有用到,稍后进行分析一下。

package com.study.chap4.imports;
import com.study.chap4.imports.pojo.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 {

    /**
     * AnnotationMetadata:当前类的注解信息
     * BeanDefinitionRegistry:BeanDefinition注册类;里面有很多方法,注册一个bean,移除一个bean等等
     * 		把所有需要添加到容器中的bean;调用
     * 		BeanDefinitionRegistry.registerBeanDefinition手工注册进来
     */
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

        boolean definition = registry.containsBeanDefinition("com.study.chap4.imports.pojo.Red");
        boolean definition2 = registry.containsBeanDefinition("com.study.chap4.imports.pojo.Blue");
        if(definition && definition2){
            //指定Bean定义信息;(Bean的类型,Bean。。。)
            RootBeanDefinition beanDefinition = new RootBeanDefinition(RainBow.class);
            //注册一个Bean,指定bean名
            registry.registerBeanDefinition("rainBow", beanDefinition);
            //移除一个bean
            registry.removeBeanDefinition("config");
        }
    }

}

 

   至此,最后我们输出可知: config确实被移除掉了。

     至此我们又新学了两个注解的用法,一个是@Conditional 另外一个是@Import,其实spring以及springboot底层都是大量运用注解写的相关代码,充分利用了注解的特性,我们把这些注解会用并且弄懂,之后看源码也不会觉得太吃力。

------------------------------------------------------------------------------------------------------------------------------------------------------------------

   这里顺便分析一个springboot启动用到的这个特性,我们首先查看springboot的启动类注解@SpringBootApplication源码,当然springboot源码启动有很多,这里不会给大家全部分析完毕,只会对用到的@import注解特性的进行分析。

 会看到里面有3个注解,一个是@ComponentScan的自定义过滤条件的扫包注入容器,该注解在本人该系列第二篇博客中完整的详细的解释到了,这里就不做过多的解释。spring5学习系列之------2 给容器注册组件二 @ComponentScan 自定义扫描规则,过滤组件接下来看第二个注解 @SpringBootConfiguration接着点进去

这是对 @Configuration注解的进行封装,在看一个注解是 @EnableAutoConfiguration ,打开这个注解的源码可看到

 重点来了,会看到一个@import注解,并且指定了一个导入的类,我们点进去,会看到用到了import的第二种方式

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值