【String注解驱动开发】如何按照条件向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) @Documented public @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; @FunctionalInterface public interface Condition { boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata); }

可以看到,Condition是一个函数式接口,对于函数式接口不了解的同学可以参见【Java8新特性】中的《》一文。也可以直接查看《Java8新特性专栏》来系统学习Java8的新特性。

所以,我们使用@Conditional注解时,需要一个类实现Spring提供的Condition接口,它会匹配@Conditional所符合的方法,然后我们可以使用我们在@Conditional注解中定义的类来检查。

@Conditional注解的使用场景如下所示。

可以作为类级别的注解直接或者间接的与@Component相关联,包括@Configuration类;

可以作为元注解,用于自动编写构造性注解;

作为方法级别的注解,作用在任何@Bean方法上。

向Spring容器注册bean 不带条件注册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()方法,如下所示。

@Test public void testAnnotationConfig6(){ ApplicationContext context = new AnnotationConfigApplicationContext(PersonConfig2.class); String[] names = context.getBeanNamesForType(Person.class); Arrays.stream(names).forEach(System.out::println); }

我们运行testAnnotationConfig6()方法,输出的结果信息如下所示。

person binghe001 binghe002

从输出结果可以看出,同时输出了binghe001和binghe002。说明默认情况下,Spring容器会将单实例并且非懒加载的bean注册到IOC容器中。

接下来,我们再输出bean的名称和bean实例对象信息,此时我们在testAnnotationConfig6()方法中添加相应的代码片段,如下所示。

@Test public 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); }

再次运行SpringBeanTest类中的testAnnotationConfig6()方法,输出结果如下所示。

person binghe001 binghe002 给容器中添加Person.... {person=Person(name=binghe002, age=18), binghe001=Person(name=binghe001, age=18), binghe002=Person(name=binghe002, age=20)}

可以看到,输出了注册到容器的bean。

带条件注册bean

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wspgdj.html