Spring Boot 2 practice: automatically configure different logical beans according to conditions

Posted by kiran_ravi on Mon, 21 Oct 2019 05:08:13 +0200

1. Preface

We often have different interfaces loaded according to conditions. For example, if you query the list of files in the directory, you will use the dir command of CMD under Windows, and you will use the ls command under Linux. Those familiar with Spring Boot auto configuration also know that Spring Boot can enable different configurations according to different actual situations. This is where @ Conditional annotation works.
This annotation specifies the conditions under which a Bean is created for configuration.

2. Comments on @ conditional

Spring Boot contains multiple @ Conditional annotations, which can be used in @ Configuration annotated classes and @ Bean annotated methods. @Annotation of Conditional type can be annotated on class, Bean method, Spring Environment property, and only when a specific resource exists. It can also be customized. Next, let's familiarize ourselves with some specific condition annotations provided by Spring Boot.

2.1 Class Conditions

@Two annotations on the class are ConditionalOnClass and @ ConditionalOnMissingClass:

Determine whether the specified class exists to build the automatic configuration, or use the name attribute name to specify the class name.

2.2 Bean Conditions

@Two annotations of ConditionalOnBean and @ ConditionalOnMissingBean on the Bean method:

To determine whether the specified Bean exists to build the automatic configuration, you can use the value attribute to specify the Bean by type or name (id), and the search attribute to specify the ApplicationContext hierarchy to search for the Bean.

@Configuration
public class MyAutoConfiguration {

    @Bean
    @ConditionalOnMissingBean
    public MyService myService() { ... }

}

To add attention to the order in which beans are added, the official recommendation is to use only the @ ConditionalOnBean and @ ConditionalOnMissingBean annotations on the auto configuration class, because these annotations can be guaranteed to execute after adding user-defined beans.

@The ConditionalOnBean and @ ConditionalOnMissingBean annotations act on the classes of the @ Configuration annotation, which is equivalent to acting on each method containing @ Bean.

2.3 Property Conditions

@The ConditionalOnProperty annotation can be judged based on the configuration contained in the Spring Environment property, and then determine the execution of automatic configuration. Use the prefix and name properties to specify the properties that should be checked. By default, matches any properties that exist and are not equal to false. You can also use the havingValue and matchIfMissing properties to create more advanced checks.

2.4 Resource Conditions

@The ConditionalOnResource annotation allows automatic configuration only when a specific resource exists. You can use the common Spring convention to specify resources, as shown in the following example: file: / home/user/test.dat.

2.5 Web Application Conditions

@The ConditionalOnWebApplication and @ ConditionalOnWebApplication annotations are used to determine whether an application is a Web application. A Web application is any application that uses Spring WebApplicationContext to define session scope or has a StandardServletEnvironment.

2.6 SpEL Expression Conditions

@The ConditionalOnExpression annotation allows configuration to be performed based on the result of a SpEL expression.

3. Custom Condition

If none of the above can meet your needs. Then we can construct the Condition by implementing the Condition interface and rewriting its matches method.

  • 1. Implement Condition interface to define judgment conditions
//Judging conditions of Windows system
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;

public class WindowsCondition implements Condition {

    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        return context.getEnvironment().getProperty("os.name").contains("Windows");
    }
}


//Judging conditions of Linux system
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;

public class LinuxCondition implements Condition {

    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        return context.getEnvironment().getProperty("os.name").contains("Linux");
    }
}
  • 2. Implement Bean classes under different systems
//Interface
public interface ListService {
    
    public String showListCmd();
}

//Implementation class under Windows
public class WindowsListServiceImpl implements ListService {

    @Override
    public String showListCmd() {
        return "dir";
    }
}

//Implementation class under Linux
public class LinuxListServiceImpl implements ListService {

    @Override
    public String showListCmd() {
        return "ls";
    }
}
  • 3. configuration class

@The Conditional annotation calls the class judged by the condition and creates the Bean based on the returned result

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ConditionConfig {
    
    @Bean
    @Conditional(WindowsCondition.class)
    public ListService windowsListService() {
        return new WindowsListServiceImpl();
    }
    
    @Bean
    @Conditional(LinuxCondition.class)
    public ListService linuxListService() {
        return new LinuxListServiceImpl();
    }
}
  • 4. run class
 @RunWith(SpringRunner.class)
 @SpringBootTest
 
 public class SecurityLearningApplicationTests {
 
     @Resource
     private ListService listService ;
     @Resource
     private ApplicationContext context;
 
 
 
 
     public void testCondition(){
         System.out.println(context.getEnvironment().getProperty("os.name")
                 + "List command under the system:"
                 + listService.showListCmd());
     }
 
 } 

4. summary

Today we have a systematic understanding of Condition judgment injection in Spring Boot. This paper not only studies some out of the box conditions provided by Spring Boot, but also implements custom conditions. If you want to learn more about the automatic configuration of Spring Boot or customize it flexibly according to the business, you must learn the Condition systematically.

Pay attention to the public account: ferrodcn for more information

Personal blog: https://felord.cn

Topics: Java Spring Windows Linux Attribute