Spring Boot 神奇的自动配置, 主要依靠大量的条件注解来使用配置自动化.
根据满足某一个特定条件创建一个特定的 Bean. 比如说, 在某些系统变量下创建 Bean, 或者只有在某个 Bean 创建后才去创建另外一个 Bean. 就是根据条件来控制 Bean 的创建行为, 可以利用该特性来进行一些自动配置.
一, 常用的条件注解
@Conditional 依赖的条件
@ConditionalOnBean 在某个 Bean 存在的条件下
@ConditionalOnMissingBean 在某个 Bean 不存在的条件下
@ConditionalOnClass 在某个 Class 存在的条件下
@ConditionalOnMissingClass 在某个 Class 不存在的条件下
比较常见的是这些注解, 还有其它的比如 @ConditionalOnwebApplication, @ConditionalOnProperty 等, 可举一反三
二, 特别说明 @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();
- }
使用 @Conditional 注解, 对象需要实现 Condition 接口, Condition 接口是一个函数式接口
- @FunctionalInterface
- public interface Condition {
- boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
- }
三, 条件注解示例
示例场景: 项目中动态的配置 MySQL 或者 Oracle 数据源
1. 定义配置文件
db-type=oracle
2. 定义 Condition 类
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"));
- }
- }
获取配置文件 db-type 的值
3. JdbcFactory 接口
- public interface JdbcFactory {
- void create();
- }
4. 默认的 MySQL 和 Oracle 实现
- 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. 测试默认实现方式
- @Resource
- private JdbcFactory jdbcFactory;
- @Test
- public void conditionOnMissBean() {
- jdbcFactory.create();
- }
结果:
Default MySQL create ..
6. 自定义实现方式
- @Component
- public class MysqlFactory implements JdbcFactory {
- @Override
- public void create() {
- System.out.println("mysql .. create");
- }
- }
7. 测试
- @Resource
- private JdbcFactory jdbcFactory;
- @Test
- public void conditionOnMissBean() {
- jdbcFactory.create();
- }
结果:
MySQL .. create
8. 解析
当环境中不存在 JdbcFactory 的 Bean 时则使用默认的实现的方式, 如例: 没有自定义实现时, 则默认使用 MySqlDefaultFactory. 这在自动化配置中会经常用到. 比如 redisTemplate 的默认实现
四, GitHub 源码
源码地址
来源: https://juejin.im/post/5c6c2189e51d45713911466d