A Brief Analysis of the Conditions Notes for Spring Boot Auto Configuration

  • 2021-06-29 11:14:12
  • OfStack

Spring Boot's amazing automatic configuration relies on a large number of conditional annotations to use configuration automation.

Create a specific Bean based on meeting a specific condition.For example, to create Bean under some system variables or another Bean only after an Bean has been created is to control the creation behavior of Bean according to conditions, which can be used for some automatic configuration.

1. Common Conditional Notes

@Conditional Dependent Conditions @ConditionalOnBean in the presence of an Bean @ConditionalOnMissingBean in the absence of an Bean @ConditionalOnClass in the presence of an Class @ConditionalOnMissingClass in the absence of an Class

It's more common to see these comments, as well as other things like @ConditionalOnWebApplication,@ConditionalOnProperty Wait, cite 1 and inverse 3

2. Specific note @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();

}

With the @Conditional annotation, the object needs to implement the Condition interface, which is a functional interface


@FunctionalInterface
public interface Condition {

 boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
}

3. Examples of conditional notes

Example scenario: Dynamic configuration of an Mysql or Oracle data source in a project

1. Define the configuration file


db-type=oracle

2. 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"));
  }
}

OracleCondition.java


public class OracleCondition implements Condition {

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

Get the value of the configuration file db-type

3. JdbcFactory interface


public interface JdbcFactory {

  void create();
}

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() {
    System.out.println("Default MySql create ..");
  }

}

Oracle


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

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

5. Test default implementation


@Resource
private JdbcFactory jdbcFactory;

@Test
public void conditionOnMissBean() {
  jdbcFactory.create();
}

Results: Default MySql create..

6. Customize implementation


@Component
public class MysqlFactory implements JdbcFactory {

  @Override
  public void create() {
    System.out.println("mysql  ....  create");
  }
}

7. Testing


@FunctionalInterface
public interface Condition {

 boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
}

0

Results: mysql.create

8. Resolution

When Bean for JdbcFactory does not exist in the environment, the default implementation is used, for example, when there is no custom implementation, MySqlDefaultFactory is used by default.This is often used in automated configurations.For example, the default implementation of redisTemplate

4. GitHub Source

Source Address


Related articles: