原创文章,转载请注明原文章地址,谢谢!
@Bean
我们知道,只要贴有@Bean注解,就会将实例注册到IoC容器中,如果在主配置类中,我们有两个实例需要注册,那么贴上@Bean注解即可。
@Configuration
public class MainConfig {
@Bean("WindowsBean")
public Person person01() {
return new Person("windows", 21);
}
@Bean("LinuxBean")
public Person person02() {
return new Person("linux", 22);
}
}
@Test
public void testConditional() {
ApplicationContext applicationContext =
new AnnotationConfigApplicationContext(SpringAnnotationApplication.class);
String[] beanNames = applicationContext.getBeanNamesForType(Person.class);
for (String beanName : beanNames) {
System.out.println(beanName);
}
Map<String, Person> beanMap = applicationContext.getBeansOfType(Person.class);
System.out.println(beanMap);
}
测试结果为:容器中的注册实例。
WindowsBean
LinuxBean
{WindowsBean=Person(name=windows, age=21), LinuxBean=Person(name=linux, age=22)}
需求
如果现在有一个需求,在主配置类中,我不需要在容器启动的时候注册所有的Bean,而是根据一定的条件判断,指定需要注册的Bean,不需要的就不注册进容器,具体点来说,判断当前的操作系统,如果是Windows系统,就把WindowsBean实例化,如果是Linux系统,就把LinuxBean实例化,在这样的需求下,该如何做呢?所以,就要用到接下来要说的注解。
@Conditional
通俗点讲,就是按照一定的条件进行判断,满足条件再给容器中注册Bean。
这里先提一下,如何获取当前的操作系统?或者说,在Spring容器中,如何获取?
基于上面那个测试类,在ApplicationContext中,其实是包含了很多信息。比如当前运行环境,类加载器,实例工厂等等。
@Test
public void testConditional() {
ApplicationContext applicationContext =
new AnnotationConfigApplicationContext(SpringAnnotationApplication.class);
Environment environment = applicationContext.getEnvironment();
//获取环境变量的值:Windows 10
String property = environment.getProperty("os.name");
System.out.println(property);
}
那么@Conditional注解该如何使用呢?先看下@Conditional注解的源码:
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {
/**
* All {@link Condition Conditions} that must {@linkplain Condition#matches match}
* in order for the component to be registered.
*/
Class<? extends Condition>[] value();
}
这个注解需要传入的是一个Condition,而且是个Class数组,也就是可以传多个条件。我们再点进去,看一下Condition是什么:
@FunctionalInterface
public interface Condition {
/**
* Determine if the condition matches.
* @param context the condition context
* @param metadata metadata of the {@link org.springframework.core.type.AnnotationMetadata class}
* or {@link org.springframework.core.type.MethodMetadata method} being checked
* @return {@code true} if the condition matches and the component can be registered,
* or {@code false} to veto the annotated component's registration
*/
boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
}
Condition是一个接口,而且是函数式接口,其有且只有一个抽象方法,接口返回值是boolean,即条件判断返回值,根据return注释信息:if the condition matches and the component can be registered,意思是,如果条件匹配为true,那么组件将会被注册。到这里,显然这是让我们实现这个接口,实现具体的判断逻辑,来决定组件是否要注册进容器。
接下来就试着来创建两个条件:LinuxCondition和WindowsCondition,分别实现Condition接口,实现matches方法,在该方法中,判断当前的操作系统,如果是Windows系统,就注册windows的Bean,如果是Linux系统,就注册linux的Bean。
public class LinuxCondition implements Condition {
/**
*
* @param conditionContext 判断条件能使用的上下文
* @param annotatedTypeMetadata 注释信息
* @return
*/
@Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
//获取到IoC使用的BeanFactory
ConfigurableListableBeanFactory beanFactory = conditionContext.getBeanFactory();
//获取类加载器
ClassLoader classLoader = conditionContext.getClassLoader();
//获取当前环境
Environment environment = conditionContext.getEnvironment();
//获取到Bean定义的注册类
BeanDefinitionRegistry registry = conditionContext.getRegistry();
String property = environment.getProperty("os.name");
if (property.contains("Linux")) {
return true;
}
return false;
}
}
public class WindowsCondition implements Condition {
@Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
//获取到IoC使用的BeanFactory
ConfigurableListableBeanFactory beanFactory = conditionContext.getBeanFactory();
//获取类加载器
ClassLoader classLoader = conditionContext.getClassLoader();
//获取当前环境
Environment environment = conditionContext.getEnvironment();
//获取到Bean定义的注册类
BeanDefinitionRegistry registry = conditionContext.getRegistry();
String property = environment.getProperty("os.name");
if (property.contains("Windows")) {
return true;
}
return false;
}
}
最后在主配置类中,贴上@Conditional注解,并指定条件。
@Configuration
public class MainConfig {
/**
* @Conditional:按照一定的条件进行判断,满足条件再给容器中注册Bean
*/
@Bean("WindowsBean")
@Conditional({WindowsCondition.class})
public Person person01() {
return new Person("windows", 21);
}
@Bean("LinuxBean")
@Conditional({LinuxCondition.class})
public Person person02() {
return new Person("linux", 22);
}
}
运行测试,查看结果:因为是在本机上测试,操作系统为Windows,所以结果只有windows的实例被注册进来。
WindowsBean
{WindowsBean=Person(name=windows, age=21)}
在这里,@Conditional注解是贴在方法上的,是针对于指定Bean,其实它也可以贴在类上,表示该类中所有Bean,都要遵循该条件注册。
@Configuration
@Conditional({LinuxCondition.class})
public class MainConfig {
/**
* @Conditional:按照一定的条件进行判断,满足条件再给容器中注册Bean
*/
@Bean("WindowsBean")
public Person person01() {
return new Person("windows", 21);
}
@Bean("LinuxBean")
public Person person02() {
return new Person("linux", 22);
}
}
测试结果:同样因为是在本机运行,是Windows系统,而给的条件是Linux才会注册,所以结果中,并没有实例注册。
{}
博客内容仅供自已学习以及学习过程的记录,如有侵权,请联系我删除,谢谢!
网友评论