1. 总览

简单说,Spring Boot 自动配置就是基于类路径上的依赖自动配置 Spring 应用的一种方式。

它可以消除掉一些可以被定义在自动配置类里的特定的 bean 的定义,从而让开发更快更轻松。

下一节,将会简单试试创建自定义 Spring Boot 自动配置

2. Maven 依赖

首先从需要的依赖开始:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
    <version>2.2.2.RELEASE</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.19</version>
</dependency>

最新版本的 spring-boot-starter-data-jpamysql-connector-java 可以从 Maven 中心仓库下载。

3. 创建自定义自动配置

创建自定义自动配置,需要创建一个被 @Configuration 注解的类并将它注册。

创建一个 MySQL 数据源的自定义配置:

@Configuration
public class MySQLAutoconfiguration {
  // ...
}

下一步必须的步骤是将这个类注册为自动配置的备选配置。将类名添加到标准文件 resources/META-INF/spring.factories 的键 org.springframework.boot.autoconfigure.EnableAutoConfiguration 里。

org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.baeldung.autoconfiguration.MySQLAutoconfiguration

如果希望自定义的自动配置类比其他自动配置备选更高的优先级,可以添加 @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE) 注解。

自动配置用在被 @Conditional 注解的类或 bean,从而自动配置或者特定的部分能够被替换。

注意:自动配置只有在自动配置的 bean 没有在应用中被定义时才会生效。如果定义了 bean,默认的将会被覆盖。

3.1 类条件

类条件允许我们在特定的类存在时使用 @ConditionalOnClass 注解指定特定的配置 bean,或是使用 @ConditionalOnMissingClass 注解指定在特定的类不存在时加载特定的配置。

这里尝试指定 MySQLConfiguration 将只会在 DataSource 类存在时加载,这时我们可以假设项目将会使用数据库连接。

@Configuration
@ConditionalOnClass(DataSource.class)
public class MySQLAutoconfiguration {
  // ...
}

3.2 bean 条件

如果想要在特定的 bean 存在或不存在时加载另一个 bean,可以使用 @ConditionalOnBean@ConditionalOnMissingBean 注解。

为了举例,添加一个 entityManagerFactory bean 到配置类里,并指定在只有在名为 dataSource 的 bean 存在,且名为 entityManagerFactory 不存在时才会创建:

@Bean
@ConditionalOnBean(name="dataSource")
@ConditionalOnMissingBean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
  LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManaagerFactoryBean();
  em.setDataSource(dataSource());
  em.setPackagesToScan("com.baeldung.autoconfiguration.example");
  em.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
  if (additionalProperties() != null) {
    em.setJpaProperties(additionalProperties());
  }
}

继续配置一个 transactionalManager bean,只会在 JpaTrasactionManager 没有定义的情况才会被加载。

@Bean
@ConditionalOnMissingBean(type="JpaTransactionManager")
JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
  JpaTransactionManager transactionManager = new JpaTransactionManager();
  transactionManager.setEntityManagerFactory(entityManagerFactory);
  return transactionManager;
}

3.3 属性条件

@ConditionalOnProperty 注解用于指定的 Spring 环境属性的值为特定的值才会加载

首先,添加一个属性源文件让配置可以从中读取属性:

@PropertySource("classpath:mysql.properties")
public class MySQLAutoconfiguration {
  // ...
}

可以配置一个主 DataSource bean,只有当属性 usemysql 存在时才会创建连接到数据库。

可以使用 havingValue 参数来指定 usemysql 的属性的值和特定值相匹配。

开始创建一个 dataSource bean,当 usemysql 被设置为 local 时,使用默认值连接到本地的名为 myDb 的数据库:

@Bean
@ConditionalOnProperty(name="usemysql", havingValue="local")
@ConditionalOnMissingBean
public DataSource dataSource() {
  DriverManagerDataSource dataSource = new DriverManagerDataSource();
  
  dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
  dataSource.setUrl("jdbc:mysql://localhost:3306/myDb?createDatabaseIfNotExist=true");
  dataSource.setUsername("mysqluser");
  dataSource.setPassword("mysqlpass");
  
  return dataSource;
}

如果 usemysql 属性设置成 customdataSource bean 将会使用自定义属性的值