Spring Boot’s amazing auto-configuration relies heavily on conditional annotations to use configuration automation.

Create a specific Bean that satisfies a specific condition. For example, create a Bean under some system variable, or create another Bean only after one Bean is created. Is to control the Bean creation behavior based on conditions, and you can use this feature for some automatic configuration.

First, commonly used conditional annotations

  • @Conditional dependent conditions
  • ConditionalOnBean Conditional on the existence of a Bean
  • ConditionalOnMissingBean in the event that a Bean does not exist
  • ConditionalOnClass in the presence of a Class
  • @ ConditionalOnMissingClass under the condition of a certain Class does not exist

More common are these annotations, and other such as @ ConditionalOnWebApplication, @ ConditionalOnProperty etc., can extrapolate

Ii. Special notes @Conditional

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {

	/**
	 * All {@link Condition Conditions} that must {@linkplain Condition#matches match}
	 * in order for the component to be registered.
	 */
	Class<? extends Condition>[] value();

}
Copy the code

Using the @Conditional annotation, objects need to implement the Condition interface, which is a functional interface

@FunctionalInterface
public interface Condition {

	boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
}

Copy the code

Examples of conditional annotations

Example scenario: dynamically configure Mysql or Oracle data sources in a project

1. Define the configuration file

db-type=mysql
Copy the code

Define the Condition class

MySqlCondition.java

public class MySqlCondition implements Condition {

    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        return "mysql".equals(context.getEnvironment().getProperty("db-type")); }}Copy the code

OracleCondition.java

public class OracleCondition implements Condition {

    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        return "oracle".equals(context.getEnvironment().getProperty("db-type")); }}Copy the code

Obtain the value of db-type in the configuration file

3. JdbcFactory interface

public interface JdbcFactory {

    void create(a);
}
Copy the code

4. Default Mysql and Oracle implementations

Mysql

@ConditionalOnMissingBean(value = JdbcFactory.class, ignored = MySqlDefaultFactory.class)
@Conditional(MySqlCondition.class)
@Component
public class MySqlDefaultFactory implements JdbcFactory {

    @Override
    public void create(a) {
        System.out.println("Default MySql create .."); }}Copy the code

Oracle

@ConditionalOnMissingBean(value = JdbcFactory.class, ignored = OracleDefaultFactory.class)
@Conditional(OracleCondition.class)
@Component
public class OracleDefaultFactory implements JdbcFactory {

    @Override
    public void create(a) {
        System.out.println("Default oracle create.."); }}Copy the code

Test the default implementation

@Resource
private JdbcFactory jdbcFactory;

@Test
public void conditionOnMissBean(a) {
    jdbcFactory.create();
}
Copy the code

Results:

Default MySql create ..
Copy the code

6. Customize the implementation mode

@Component
public class MysqlFactory implements JdbcFactory {

    @Override
    public void create(a) {
        System.out.println("Mysql.. create"); }}Copy the code

7. Test

@Resource
private JdbcFactory jdbcFactory;

@Test
public void conditionOnMissBean(a) {
    jdbcFactory.create();
}
Copy the code

Results:

Mysql.. createCopy the code

Analytical 8.

The default implementation is used when there is no JdbcFactory Bean in the environment, for example, MySqlDefaultFactory is used by default when there is no custom implementation. This is often used in automated configurations. Such as the default implementation of redisTemplate

GitHub source code

The source address