美文网首页
Spring注解:@Conditional

Spring注解:@Conditional

作者: 因你而在_caiyq | 来源:发表于2020-04-11 20:34 被阅读0次

原创文章,转载请注明原文章地址,谢谢!

@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才会注册,所以结果中,并没有实例注册。

{}

博客内容仅供自已学习以及学习过程的记录,如有侵权,请联系我删除,谢谢!

相关文章

网友评论

      本文标题:Spring注解:@Conditional

      本文链接:https://www.haomeiwen.com/subject/ijqaphtx.html