如何按照条件向Spring容器中注册bean?这次我懂了

写在前面

当bean是单实例,并且没有设置懒加载时,Spring容器启动时,就会实例化bean,并将bean注册到IOC容器中,以后每次从IOC容器中获取bean时,直接返回IOC容器中的bean,不再创建新的bean 。
如果bean是单实例,并且使用@Lazy注解设置了懒加载,则Spring容器启动时,不会实例化bean,也不会将bean注册到IOC容器中,只有第一次获取bean的时候,才会实例化bean,并且将bean注册到IOC容器中 。
如果bean是多实例,则Spring容器启动时,不会实例化bean,也不会将bean注册到IOC容器中,以后每次从IOC容器中获取bean时,都会创建一个新的bean返回 。
Spring支持按照条件向IOC容器中注册bean,满足条件的bean就会被注册到IOC容器中,不满足条件的bean就不会被注册到IOC容器中 。接下来,我们就一起来探讨Spring中如何实现按照条件向IOC容器中注册bean 。
项目工程源码已经提交到GitHub:https://github.com/sunshinelyz/spring-annotation
@Conditional注解概述@Conditional注解可以按照一定的条件进行判断,满足条件向容器中注册bean,不满足条件就不向容器中注册bean 。
@Conditional注解是由 SpringFramework 提供的一个注解,位于 org.springframework.context.annotation 包内,定义如下 。
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)@Documentedpublic @interface Conditional { Class<? extends Condition>[] value();}从@Conditional注解的源码来看,@Conditional注解可以添加到类上,也可以添加到方法上 。在@Conditional注解中,存在一个Condition类型或者其子类型的Class对象数组,Condition是个啥?我们点进去看一下 。
package org.springframework.context.annotation;import org.springframework.beans.factory.config.BeanFactoryPostProcessor;import org.springframework.core.type.AnnotatedTypeMetadata;@FunctionalInterfacepublic interface Condition { boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);}【如何按照条件向Spring容器中注册bean?这次我懂了】可以看到,Condition是一个函数式接口,对于函数式接口不了解的同学可以参见【Java8新特性】中的《【Java8新特性】还没搞懂函数式接口?赶快过来看看吧!》一文 。也可以直接查看《Java8新特性专栏》来系统学习Java8的新特性 。
所以,我们使用@Conditional注解时,需要一个类实现Spring提供的Condition接口,它会匹配@Conditional所符合的方法,然后我们可以使用我们在@Conditional注解中定义的类来检查 。
@Conditional注解的使用场景如下所示 。
  • 可以作为类级别的注解直接或者间接的与@Component相关联,包括@Configuration类;
  • 可以作为元注解,用于自动编写构造性注解;
  • 作为方法级别的注解,作用在任何@Bean方法上 。
向Spring容器注册bean不带条件注册bean
如何按照条件向Spring容器中注册bean?这次我懂了

文章插图
 
 我们在PersonConfig2类中新增person01()方法和person02()方法,并为两个方法添加@Bean注解,如下所示 。
@Bean("binghe001")public Person person01(){return new Person("binghe001", 18);}@Bean("binghe002")public Person person02(){return new Person("binghe002", 20);}那么,这两个bean默认是否会被注册到Spring容器中呢,我们新建一个测试用例来测试一下 。在SpringBeanTest类中新建testAnnotationConfig6()方法,如下所示 。
@Testpublic void testAnnotationConfig6(){ApplicationContext context = new AnnotationConfigApplicationContext(PersonConfig2.class);String[] names = context.getBeanNamesForType(Person.class);Arrays.stream(names).forEach(System.out::println);}我们运行testAnnotationConfig6()方法,输出的结果信息如下所示 。
personbinghe001binghe002从输出结果可以看出,同时输出了binghe001和binghe002 。说明默认情况下,Spring容器会将单实例并且非懒加载的bean注册到IOC容器中 。
接下来,我们再输出bean的名称和bean实例对象信息,此时我们在testAnnotationConfig6()方法中添加相应的代码片段,如下所示 。
@Testpublic void testAnnotationConfig6(){ApplicationContext context = new AnnotationConfigApplicationContext(PersonConfig2.class);String[] names = context.getBeanNamesForType(Person.class);Arrays.stream(names).forEach(System.out::println);Map<String, Person> beans = context.getBeansOfType(Person.class);System.out.println(beans);}


推荐阅读