前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >一文了解ConfigurationConditon 接口

一文了解ConfigurationConditon 接口

作者头像
cxuan
发布2019-08-06 09:55:58
5700
发布2019-08-06 09:55:58
举报
文章被收录于专栏:Java建设者

@Conditional 和 Condition

在了解ConfigurationCondition 接口之前,先通过一个示例来了解一下@Conditional 和 Condition。(你也可以通过 https://www.cnblogs.com/cxuanBlog/p/10960575.html 详细了解)

  • 首先新建一个Maven项目(可以使用SpringBoot快速搭建),添加Spring4.0 的pom.xml 依赖
代码语言:javascript
复制
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.5.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.cxuan.configuration</groupId>
    <artifactId>configuration-condition</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>configuration-condition</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
        <spring.version>4.3.13.RELEASE</spring.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>
  • 新建一个IfBeanAExistsCondition 类,该类继承了Condition接口,提供某些注册条件的逻辑
代码语言:javascript
复制
public class IfBeanAExistsCondition implements Condition {

    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        boolean IfContainsbeanA = context.getBeanFactory().containsBeanDefinition("beanA");
        return IfContainsbeanA;
    }
}

Condition是一个接口,里面只有一个方法就是matches,上述表明如果ConditionContext的beanFactory包括名称为beanA的bean就返回true,否则返回false不进行注册。

  • 为了测试Condition是否可用,我们新建一个ConfigurationConditionApplication类,注册两个Bean分别为BeanA和BeanB,BeanB的注册条件是BeanA首先进行注册,采用手动注册和刷新的方式。详见https://www.cnblogs.com/cxuanBlog/p/10958307.html,具体代码如下:
代码语言:javascript
复制
public class ConfigurationConditionApplication {

    private static void loadContextAndVerifyBeans(Class...classToRegistry){
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        context.register(classToRegistry);
        context.refresh();
        System.out.println("Has BeanA? " + context.containsBean("beanA"));
        System.out.println("Has BeanB? " + context.containsBean("beanB"));
    }


    public static void main(String[] args) {
        loadContextAndVerifyBeans(BeanA.class);
        loadContextAndVerifyBeans(BeanA.class,BeanB.class);
        loadContextAndVerifyBeans(BeanB.class);
        loadContextAndVerifyBeans(BeanB.class,BeanA.class);
    }
}

@Configuration()
class BeanA{}

@Conditional(IfBeanAExistsCondition.class)
@Configuration()
class BeanB{}

输出结果:

代码语言:javascript
复制
...
Has BeanA? true
Has BeanB? false
...
Has BeanA? true
Has BeanB? true
...
Has BeanA? false
Has BeanB? false
...
Has BeanA? true
Has BeanB? false

来解释一下上面的输出结果,第一次只注册了一个BeanA的bean,@Configuration标注的BeanA默认注册的definitionName为beanA,首字母小写。

第二次同时传入了BeanA.class 和 BeanB.class, 由于BeanB的注解上标明@Conditional(IfBeanAExistsCondition.class)表示的是注册BeanA之后才会注册BeanB,所以注册了beanA,因为beanA被注册了,所以同时也就注册了beanB。

第三次只传入了BeanB.class,因为没有注册BeanA和BeanB,所以两次输出都是false。

第四次先传入了BeanB.class,后又传入了BeanA.class,根据加载顺序来看,BeanB.class 首先被加载,然后是BeanA.class 被加载,BeanB被加载的时候BeanA.class 还没有被注入,之后BeanA才会注入,所以输出的结果是true和false。

上述例子可以把BeanA和BeanB类放入ConfigurationConditionApplication中,类似

代码语言:javascript
复制
public class ConfigurationConditionApplication {

@Configuration()
static class BeanA{}

@Conditional(IfBeanAExistsCondition.class)
@Configuration()
static class BeanB{}

}

但是需要把BeanA和BeanB定义为静态类,因为静态类与外部类无关能够独立存在,如果定义为非静态的,启动会报错。

关于ConfigurationConditon

ConfigurationCondition接口是Spring4.0提供的注解。位于org.springframework.context.annotation包内,继承于Condition接口。Condition接口和@Configuration以及@Conditional接口为bean的注册提供更细粒度的控制,允许某些Condition在匹配时根据配置阶段进行调整。

代码语言:javascript
复制
public interface ConfigurationCondition extends Condition {

    // 评估condition返回的ConfigurationPhase
    ConfigurationPhase getConfigurationPhase();

    // 可以评估condition的各种配置阶段。
    enum ConfigurationPhase {

        // @Condition 应该被评估为正在解析@Configuration类
        // 如果此时条件不匹配,则不会添加@Configuration 类。
        PARSE_CONFIGURATION,

        // 添加常规(非@Configuration)bean时,应评估@Condition。Condition 将不会阻止@Configuration 类
        // 添加。在评估条件时,将解析所有@Configuration
        REGISTER_BEAN
    }

}

getConfigurationPhase()方法返回ConfigurationPhase 的枚举。枚举类内定义了两个enum,PARSE_CONFIGURATION 和 REGISTER_BEAN,表示不同的注册阶段。

我们现在对condition实现更细粒度的控制,实现了ConfigurationCondition接口,我们现在需要实现getConfigurationPhase()方法获得condition需要评估的阶段。

  • 新建IfBeanAExistsConfigurationCondition类,实现了ConfigurationCondition接口,分别返回ConfigurationPhase.REGISTER_BEAN 和 ConfigurationPhase.PARSE_CONFIGURATION 阶段。
代码语言:javascript
复制
public class IfBeanAExistsConfigurationCondition implements ConfigurationCondition {

    @Override
    public ConfigurationPhase getConfigurationPhase() {
        return ConfigurationPhase.REGISTER_BEAN;
    }

//    @Override
//    public ConfigurationPhase getConfigurationPhase() {
//        return ConfigurationPhase.PARSE_CONFIGURATION;
//    }

    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        return context.getBeanFactory().containsBeanDefinition("beanA");
    }
}
  • 新建SpringConfigurationConditionExample类,与上述测试类基本相同,就是把@Conditional 换为了@Conditional(IfBeanAExistsConfigurationCondition.class)

测试类启动,输出结果

代码语言:javascript
复制
...
Has BeanA? true
Has BeanB? false
...
Has BeanA? true
Has BeanB? true
...
Has BeanA? false
Has BeanB? false
...
Has BeanA? true
Has BeanB? true
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-08-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Java建设者 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • @Conditional 和 Condition
  • 关于ConfigurationConditon
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档