一文了解ConfigurationConditon 接口

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

@Conditional 和 Condition

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

  • 首先新建一个Maven项目(可以使用SpringBoot快速搭建),添加Spring4.0 的pom.xml 依赖
<?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接口,提供某些注册条件的逻辑
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,具体代码如下:
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{}

输出结果:

...
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中,类似

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在匹配时根据配置阶段进行调整。

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 阶段。
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)

测试类启动,输出结果

...
Has BeanA? true
Has BeanB? false
...
Has BeanA? true
Has BeanB? true
...
Has BeanA? false
Has BeanB? false
...
Has BeanA? true
Has BeanB? true

也就是说,如果返回的是PARSE_CONFIGURATION阶段的话,不会阻止@Configuration的标记类的注册顺序,啥意思呢?

第一个结果,只注册了BeanA,因为只有BeanA加载。

第二个结果,注册了BeanA和BeanB,因为BeanA和BeanB都被加载

第三个结果,因为BeanB注册的条件是BeanA注册,因为BeanA没有注册,所以BeanB不会注册

第四个结果,不论BeanA和BeanB的加载顺序如何,都会直接进行注册。

  • 如果把REGISTER_BEAN改为**PARSE_CONFIGURATION **,会发现加载顺序第一次一致。
相关文章
|
人工智能 供应链 监控
【AI 现况分析】AI 在机械制造领域的应用分析
【1月更文挑战第27天】【AI 现况分析】AI 在机械制造领域的应用分析
|
存储 搜索推荐 安全
Onlyfans如何使用搜索功能?Onlyfans如何搜索博主?如何在OnlyFans搜索HongkongDoll
本文是一份全面的指南,旨在帮助读者了解如何在OnlyFans平台上有效使用搜索功能,尤其是如何找到特定的博主,比如HongkongDoll。我们深入探讨了OnlyFans的搜索机制,包括其对用户隐私的重视以及因此带来的搜索限制。文章详细介绍了三种主要的搜索方法:使用OnlyFans的官方搜索服务、通过社交媒体链接进行跳转、以及利用第三方搜索引擎如OnlySearch。
|
机器学习/深度学习 人工智能 算法
量子计算与化学:分子模拟的新技术
量子计算在化学领域的应用正逐步改变分子模拟的传统方式。基于量子力学原理,量子计算机能高效处理复杂分子的量子态,优化分子结构,模拟化学反应及电子结构计算,为新材料设计、药物研发等提供新途径。尽管当前技术仍面临稳定性与可扩展性的挑战,但其未来发展前景广阔,有望为化学研究带来革命性变化。
530 35
|
人工智能 数据中心 芯片
液冷是大模型对算力需求的必然选择?|英伟达 GTC 2024六大亮点
在这个以高性能计算和大模型推动未来通用人工智能时代,算力已成为科技发展的隐形支柱。本文将重点探讨算力的演进,深入分析在不同领域中算力如何成为推动进步的基石;着眼于液冷如何突破算力瓶颈成为引领未来的先锋,对液冷散热的三种方式(冷板式、浸没式和喷淋式)做了详细的对比分析、成本测算和市场空间预测。并为您提供一份“实用教程”,指导如何将普通服务器改装为液冷服务器,以应对越来越复杂的计算需求。
|
芯片 内存技术
什么是内存颗粒?内存条的构成!
什么是内存颗粒?内存条的构成!
1142 0
什么是内存颗粒?内存条的构成!
|
存储 缓存 网络协议
TCP vs UDP:揭秘可靠性与效率之争
在网络通信中,TCP和UDP是两种最常用的传输层协议。本文将深入探讨TCP和UDP之间的区别,包括连接方式、服务对象、拥塞控制、流量控制和首部开销等方面,帮助读者在不同应用需求下选择适合的协议。无论你是技术爱好者还是网络工程师,这篇文章定能帮助你了解并应用TCP和UDP的差异,提升你的网络传输效率和可靠性。
1724 1
|
自然语言处理 数据挖掘 Java
银行常用的编程语言
银行常用的编程语言
[贴装专题] 基于halcon的最小二乘法计算吸嘴或机械轴旋转中心
[贴装专题] 基于halcon的最小二乘法计算吸嘴或机械轴旋转中心
482 0
|
前端开发 程序员 数据库
程序员需要知道的50个网址,包括编程社区、开发工具、技术博客、在线课程等。
以下是 50 个程序员必须要知道的网站: 1. Codecademy(www.codecademy.com):在线编程学习平台,提供多种编程语言的入门课程。 2. Khan Academy(www.khanacademy.org):非营利性在线学习平台,提供有关计算机科学和编程的免费课程。 3. Udemy(www.udemy.com):在线教育平台,提供大量编程课程,包括入门课程和进阶课程。 4. Coursera(www.coursera.org):在线教育平台,提供全球顶尖大学和机构的编程课程。 5. edX(www.edx.org):在线教育平台,提供全球顶尖大学和机构的编程课程。 6
936 0
|
算法 程序员
程序员可能越来越排斥面试时做题的原因
程序员可能越来越排斥面试时做题的原因
405 1