SpringBoot automatic assembly-@Conditional conditional assembly and custom Starter

1. @Conditional

@Conditional is mainly used to provide conditional constraints for automatic assembly , and is generally used in conjunction with @Configuration and @Bean.

1.1 @Conditional

First look at its structure:

@Target({
    
    ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {
    
    
    Class<? extends Condition>[] value();
}

It can be seen that the annotation can receive an array of Condition type. Condition is a functional interface, mainly used to provide a matches method, ** provides a conditional matching rule, return true to indicate that Bean can be injected, otherwise, it is not injected.
**

@FunctionalInterface
public interface Condition {
    
    
    boolean matches(ConditionContext var1, AnnotatedTypeMetadata var2);
}

Case 1: @Conditional realizes conditional assembly

Custom Condition:

public class MyCondition implements Condition {
    
    
    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
    
    
        String os = conditionContext.getEnvironment().getProperty("os.name");
        // 如果电脑运行环境是Mac,那么返回true
        // 如果你的电脑是window,这里输入Windows
        if (os.contains("Mac OS X")) {
    
    
            return true;
        }
        return false;
    }
}

Custom configuration class:

@Configuration
public class ConditionConfig {
    
    
	
    @Conditional(MyCondition.class)
    @Bean
    // 只有MyCondition返回true时,这里才会加载这个Bean
    public FirstBean getBean(){
    
    
        return new FirstBean();
    }
}

Startup class:

@SpringBootApplication
public class DemoApplication {
    
    

    public static void main(String[] args) {
    
    
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ConditionConfig.class);
        // FirstBean是我自定义的Bean
        FirstBean bean = context.getBean(FirstBean.class);
        System.out.println(bean.toString());
    }
}

Result: Insert picture description here
If you change the logic at this time, such as returning true when the environment is Window, then the result will report an error, the error is as follows:
Insert picture description here

1.2 @Conditional in SpringBoot

In SpringBoot, @Conditional has been expanded. The expanded annotations are as follows:

  • ConditionalOnBean/ConditionalMissingBean: Bean loading is performed when a certain class or no Bean exists in the container.
  • ConditionalOnClass/ConditionalMissingClass: Bean loading is performed when the specified class exists or does not exist on the classpath.
  • ConditionalOnCloudPlatForm: Load the specified Bean only when it runs on the specified cloud platform.
  • ConditionalOnExpression: Conditional judgment based on spEL expression.
  • ConditionalOnJava: Bean will be loaded only when the specified version of Java is running.
  • ConditionalOnJndi: Load the Bean only after the specified resource is loaded through JNDI.
  • ConditionalOnWebApplication/ConditionalOnNotWebApplication: Load the Bean if it is a web application or not.
  • ConditionalOnProperty: Whether the corresponding property specified in the system has a corresponding value, will the bean be loaded.
  • ConditionalOnResource: The Bean to be loaded depends on whether the specified resource exists in the classpath.
  • ConditionalOnSingleCandidate: Bean will only be loaded when a single candidate for a given Bean class is determined.

These annotations only need to be added to the class level or method level of the @Configuration configuration class, and parameters can be passed according to the role of each annotation.

Case 2: @Conditional extension

ConditionalOnProperty:

  • This class will only be loaded when test.bean.enble=true in the application.properties or application.yml file
  • If there is no match, it will be loaded because matchIfMissing=true (default is false)
@Configuration
@ConditionalOnProperty(value = "test.bean.enble", havingValue = "true", matchIfMissing = true)
public class ConditionConfig {
    
    

}

ConditionalOnBean:

  • Only the FirstBean class exists in the container, the ConditionConfig will be assembled
@Configuration
@ConditionalOnBean(FirstBean.class)
public class ConditionConfig {
    
    

}

ConditionalOnResource:

  • If the test.properties file exists in the classpath, the ConditionConfig will be automatically loaded.
@Configuration
@ConditionalOnResource(resources = "/test.properties")
public class ConditionConfig {
    
    

}

1.3 spring-autoconfigure-metadata

In addition to the @Conditional annotation class, the spring-autoconfigure-metadata.properties file is also provided in SpringBoot to realize the conditional configuration of batch automatic assembly.

It works the same as @Conditional, except that these condition configurations are placed in the configuration file. At the same time, two conditions must be followed to implement conditional filtering through this configuration method:

  • The path and name of the configuration file must be /META-INF/spring-autoconfigure-metadata.properties
  • The format of the key in the configuration file: the full path name of the automatic configuration class. Condition=value

Advantage:

  • It can effectively reduce the startup time of SpringBoot. This filtering method can reduce the number of configuration classes loaded. Because this filtering occurs before the loading of configuration classes, it can reduce the time consumption of loading Beans when SpringBoot starts.

2. Starter

The Starter component has three main functions:

  • Involving the Jar package dependencies of related components.
  • Automatic realization of Bean assembly.
  • Automatically declare and load the property configuration in the application.properties file.

Starter naming convention:

  • Official naming format: spring-boot-starter-module name
  • Custom naming format: module name-spring-boot-starter

Case 3: Customize a Starter based on Redis

Project structure:
Insert picture description here
Custom configuration class RedisAutoConfiguration:

  • Define the configuration class that needs to be automatically assembled, mainly to assemble the RedissonClient into the IOC container.
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.redisson.config.SingleServerConfig;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;

@Configuration
@ConditionalOnClass(Redisson.class)
@EnableConfigurationProperties(RedissonProperties.class)
public class RedisAutoConfiguration {
    
    

    RedissonClient redissonClient(RedissonProperties redissonProperties) {
    
    
        Config config = new Config();
        String prefix = "redis://";
        if (redissonProperties.isSsl()) {
    
    
            prefix = "rediss://";
        }
        SingleServerConfig singleServerConfig = config.useSingleServer().setAddress(prefix + redissonProperties.getHost() + ":" + redissonProperties.getPort())
                .setConnectTimeout(redissonProperties.getTimeout());
        if (!StringUtils.isEmpty(singleServerConfig)) {
    
    
            singleServerConfig.setPassword(redissonProperties.getPassword());
        }
        return Redisson.create(config);
    }
}

Custom configuration class RedissonProperties:

  • Define the property class and configure the Redis connection parameters in application.properties.
  • The function of @ConfigurationPropertie is to bind the properties of the current class to the configuration in the configuration file (properties/yml), and the prefix is ​​my.redisson
import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties(prefix = "my.redisson")
public class RedissonProperties {
    
    
    private String host="localhost";
    private String password;
    private int port=6379;
    private int timeout;
    private boolean ssl;

    public String getHost() {
    
    
        return host;
    }

    public void setHost(String host) {
    
    
        this.host = host;
    }

    public String getPassword() {
    
    
        return password;
    }

    public void setPassword(String password) {
    
    
        this.password = password;
    }

    public int getPort() {
    
    
        return port;
    }

    public void setPort(int port) {
    
    
        this.port = port;
    }

    public int getTimeout() {
    
    
        return timeout;
    }

    public void setTimeout(int timeout) {
    
    
        this.timeout = timeout;
    }

    public boolean isSsl() {
    
    
        return ssl;
    }

    public void setSsl(boolean ssl) {
    
    
        this.ssl = ssl;
    }
}

spring.factories:

  • The purpose is to allow the SpringBoot program to scan the file to complete automatic assembly. The key and value correspond to the following:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.config.RedisAutoConfiguration

application.properties:

  • Set the property configuration.
  • This property will be automatically bound to the corresponding property defined in RedissonProperties.
my.redission=192.168.237.130
my.redission.port=6379

pom:

  • Add starter dependency (redis-spring-boot-starter)
<parent>
    <groupId>org.springframework.boot</groupId>
    <version>2.3.5.RELEASE</version>
    <artifactId>spring-boot-starter-parent</artifactId>
</parent>
<dependencies>
    <dependency>
        <groupId>org.redisson</groupId>
        <artifactId>redisson</artifactId>
        <version>3.11.1</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-configuration-processor</artifactId>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.example</groupId>
        <artifactId>redis-spring-boot-starter</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
</dependencies>

After completing the above steps, a simple handwritten Starter is completed.

Guess you like

Origin blog.csdn.net/Zong_0915/article/details/112968640