Article for ConfigurationConditon Interface

ConfigurationCondition Interface Description

@Conditional 和 Condition

Before understanding ConfigurationCondition interfaces, first take a look at an example @Conditional and Condition. (You can learn more by https://www.cnblogs.com/cxuanBlog/p/10960575.html)

  • First create a new Maven project (you can use SpringBoot quickly build), add the pom.xml rely Spring4.0
<?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>
  • Create a new IfBeanAExistsConditionclass that inherits Condition interface, providing some logic registration conditions
public class IfBeanAExistsCondition implements Condition {

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

Condition is an interface, which is only one way that matches, if ConditionContext above shows that the beanFactory include the name and returns true as beanA of bean, false otherwise not be registered.

  • To test Condition is available, we create a new ConfigurationConditionApplicationclass, registered two were BeanA Bean and BeanB, registration conditions BeanB is BeanA register first, manual registration and refreshing way. See https://www.cnblogs.com/cxuanBlog/p/10958307.html, specific code as follows:
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{}

Output:

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

Explain the above output, only the first time registered a BeanA of bean, @ Configuration annotation BeanA default registered definitionName as beanA, the first letter lowercase.

The second passing in the BeanA.class and BeanB.class, due to the marked @Conditional (IfBeanAExistsCondition.class) on notes BeanB represented only registered after the registration BeanA BeanB, so registered beanA, because beanA been registered, so while it registered a beanB.

Third only passed in BeanB.class, because there is no registered BeanA and BeanB, so the two outputs are false.

Fourth first introduced to BeanB.class, then passed the BeanA.class, according to loading order point of view, BeanB.class be loaded first, then BeanA.class loaded, BeanB also be loaded when BeanA.class not injected, after BeanA will be injected, so the output is the result of true and false.

The above examples and BeanB BeanA classes in ConfigurationConditionApplication, like

public class ConfigurationConditionApplication {
   
@Configuration()
static class BeanA{}

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

But the need to BeanA and BeanB defined as a static class, because the static class has nothing to do with the external class can exist independently, if defined as non-static, start error.

About ConfigurationConditon

ConfigurationCondition interface is a comment Spring4.0 provided. Located org.springframework.context.annotation encapsulated, inherited from the Condition interface. Condition interfaces and interfaces @Conditional @Configuration and provide more fine-grained control bean is registered, allowing some adjustment in accordance with Condition phase matching configuration.

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 () method returns ConfigurationPhase enumeration. Within the enumeration class defines two enum, PARSE_CONFIGURATION and REGISTER_BEAN, represent different stages of registration.

We now realize the condition is more fine-grained control, to achieve ConfigurationCondition interface, we now need to implement getConfigurationPhase () method to obtain phase condition needs to be evaluated.

  • New IfBeanAExistsConfigurationConditionclass that implements the interface ConfigurationCondition, return the ConfigurationPhase.REGISTER_BEAN and ConfigurationPhase.PARSE_CONFIGURATION stage.
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");
    }
}
  • New SpringConfigurationConditionExampleclass, the class the test is substantially the same as described above, is to change the @Conditional @Conditional (IfBeanAExistsConfigurationCondition.class)

Test classes start, output

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

That is, if the return is PARSE_CONFIGURATION stage of the case, the order does not prevent the registration of marks @Configuration class, what does it mean?

The first result, only registered BeanA, because only BeanA loaded.

The second result, registered BeanA and BeanB, because BeanA and BeanB are loaded

The third result, because the conditions BeanB registration is BeanA registration because BeanA not registered, not registered so BeanB

The fourth result, regardless of load order BeanA and BeanB , will directly register.

  • If REGISTER_BEAN changed PARSE_CONFIGURATION , you will find the same load order for the first time.

Guess you like

Origin www.cnblogs.com/cxuanBlog/p/10961895.html