1. 概要

簡単に言うと、Spring Bootの自動構成は、クラスパスに存在する依存関係に基づいてSpringアプリケーションを自動的に構成する方法を表しています。

これにより、自動構成クラスに含まれる特定のBeanを定義する必要がなくなるため、開発がより迅速かつ容易になります。

次のセクションでは、カスタムSpring Boot自動構成の作成について見ていきます。

2. Mavenの依存関係

必要な依存関係から始めましょう:

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

spring-boot-starter-data-jpaおよびmysql-connector-javaの最新バージョンは、MavenCentralからダウンロードできます。

3. カスタム自動構成の作成

カスタム自動構成を作成するには、@Configurationという注釈の付いたクラスを作成して登録する必要があります。

MySQLデータソースのカスタム構成を作成しましょう。

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

次の必須ステップは、標準ファイル resources /METAのキーorg.springframework.boot.autoconfigure.EnableAutoConfigurationの下にクラスの名前を追加することにより、クラスを自動構成候補として登録することです。 -INF / spring.factories

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

自動構成クラスを他の自動構成候補よりも優先させたい場合は、 @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)アノテーションを追加できます。

自動構成は、 @Conditional アノテーションが付けられたクラスとBeanを使用して設計されているため、自動構成またはその特定の部分を置き換えることができます。

自動構成は、自動構成されたBeanがアプリケーションで定義されていない場合にのみ有効であることに注意してください。 Beanを定義すると、デフォルトのBeanがオーバーライドされます。

3.1. クラス条件

クラス条件を使用すると、 @ConditionalOnClass アノテーションを使用して、指定されたクラスが存在する場合を使用して、またはクラスが存在しない場合を使用して、構成Beanを含めるように指定できます。 @ConditionalOnMissingClassアノテーション。

MySQLConfiguration がロードされるのは、クラス DataSource が存在する場合のみであると指定しましょう。この場合、アプリケーションはデータベースを使用すると想定できます。

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

3.2. 豆の状態

指定されたBeanが存在するかどうかの場合にのみBeanを含める場合は、@ConditionalOnBeanおよび@ConditionalOnMissingBeanアノテーションを使用できます。

これを例示するために、 entityManagerFactory Beanを構成クラスに追加し、 dataSource というBeanが存在し、というBeanが存在する場合にのみ、このBeanを作成するように指定します。 ] entityManagerFactory はまだ定義されていません:

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

タイプJpaTransactionManagerのBeanがまだ定義されていない場合にのみロードされるtransactionManagerBeanも構成しましょう。

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

3.3. 物件条件

@ConditionalOnProperty アノテーションは、SpringEnvironmentプロパティの存在と値に基づいて構成をロードするかどうかを指定するために使用されます。

まず、プロパティがどこから読み取られるかを決定する構成のプロパティソースファイルを追加しましょう。

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

usemysql というプロパティが存在する場合にのみロードされるように、データベースへの接続を作成するために使用されるメインのDataSourceBeanを構成できます。

属性havingValueを使用して、一致する必要のあるusemysqlプロパティの特定の値を指定できます。

usemysqlプロパティがlocalに設定されている場合、myDbというローカルデータベースに接続するデフォルト値を使用してdataSourceBeanを定義しましょう。

@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プロパティがcustomに設定されている場合、 dataSource Beanは、データベースURL、ユーザー、およびパスワードのカスタムプロパティ値を使用して構成されます。

@Bean(name = "dataSource")
@ConditionalOnProperty(
  name = "usemysql", 
  havingValue = "custom")
@ConditionalOnMissingBean
public DataSource dataSource2() {
    DriverManagerDataSource dataSource = new DriverManagerDataSource();
        
    dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
    dataSource.setUrl(env.getProperty("mysql.url"));
    dataSource.setUsername(env.getProperty("mysql.user") != null 
      ? env.getProperty("mysql.user") : "");
    dataSource.setPassword(env.getProperty("mysql.pass") != null 
      ? env.getProperty("mysql.pass") : "");
        
    return dataSource;
}

mysql.properties ファイルには、usemysqlプロパティが含まれます。

usemysql=local

MySQLAutoconfiguration を使用するアプリケーションがデフォルトのプロパティを上書きしたい場合は、 mysql.url mysql.userに異なる値を追加するだけです。およびmysql.passプロパティとmysql.propertiesファイルのusemysql=custom行。

3.4. リソース条件

@ConditionalOnResource アノテーションを追加すると、構成は、指定されたリソースが存在する場合にのみロードされます

リソースファイルの場合にのみ、 entityManagerFactory Beanによって使用されるHibernate固有のプロパティを含むPropertiesオブジェクトを返すadditionalProperties()というメソッドを定義しましょう。 mysql.properties が存在します:

@ConditionalOnResource(
  resources = "classpath:mysql.properties")
@Conditional(HibernateCondition.class)
Properties additionalProperties() {
    Properties hibernateProperties = new Properties();

    hibernateProperties.setProperty("hibernate.hbm2ddl.auto", 
      env.getProperty("mysql-hibernate.hbm2ddl.auto"));
    hibernateProperties.setProperty("hibernate.dialect", 
      env.getProperty("mysql-hibernate.dialect"));
    hibernateProperties.setProperty("hibernate.show_sql", 
      env.getProperty("mysql-hibernate.show_sql") != null 
      ? env.getProperty("mysql-hibernate.show_sql") : "false");
    return hibernateProperties;
}

Hibernate固有のプロパティをmysql.propertiesファイルに追加できます。

mysql-hibernate.dialect=org.hibernate.dialect.MySQLDialect
mysql-hibernate.show_sql=true
mysql-hibernate.hbm2ddl.auto=create-drop

3.5. カスタム条件

Spring Bootで使用可能な条件を使用したくない場合は、SpringBootConditionクラスを拡張し、getMatchOutcome()メソッドをオーバーライドすることで、カスタム条件を定義することもできます。

additionalProperties()メソッドの HibernateCondition という条件を作成して、HibernateEntityManagerクラスがクラスパスに存在するかどうかを確認します。

static class HibernateCondition extends SpringBootCondition {

    private static String[] CLASS_NAMES
      = { "org.hibernate.ejb.HibernateEntityManager", 
          "org.hibernate.jpa.HibernateEntityManager" };

    @Override
    public ConditionOutcome getMatchOutcome(ConditionContext context, 
      AnnotatedTypeMetadata metadata) {
 
        ConditionMessage.Builder message
          = ConditionMessage.forCondition("Hibernate");
        return Arrays.stream(CLASS_NAMES)
          .filter(className -> ClassUtils.isPresent(className, context.getClassLoader()))
          .map(className -> ConditionOutcome
            .match(message.found("class")
            .items(Style.NORMAL, className)))
          .findAny()
          .orElseGet(() -> ConditionOutcome
            .noMatch(message.didNotFind("class", "classes")
            .items(Style.NORMAL, Arrays.asList(CLASS_NAMES))));
    }
}

次に、条件を additionalProperties()メソッドに追加できます。

@Conditional(HibernateCondition.class)
Properties additionalProperties() {
  //...
}

3.6. 使用条件

@ConditionalOnWebApplicationまたは@ConditionalOnNotWebApplicationアノテーションを追加することにより、構成をWebコンテキストの内部/外部でのみロードできるように指定することもできます。

4. 自動構成のテスト

自動構成をテストするための非常に簡単な例を作成しましょう。 Spring Dataを使用して、 MyUser というエンティティクラスと、MyUserRepositoryインターフェイスを作成します。

@Entity
public class MyUser {
    @Id
    private String email;

    // standard constructor, getters, setters
}
public interface MyUserRepository 
  extends JpaRepository<MyUser, String> { }

自動構成を有効にするには、@SpringBootApplicationまたは@EnableAutoConfigurationアノテーションのいずれかを使用できます。

@SpringBootApplication
public class AutoconfigurationApplication {
    public static void main(String[] args) {
        SpringApplication.run(AutoconfigurationApplication.class, args);
    }
}

次に、MyUserエンティティを保存するJUnitテストを作成しましょう。

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(
  classes = AutoconfigurationApplication.class)
@EnableJpaRepositories(
  basePackages = { "com.baeldung.autoconfiguration.example" })
public class AutoconfigurationTest {

    @Autowired
    private MyUserRepository userRepository;

    @Test
    public void whenSaveUser_thenOk() {
        MyUser user = new MyUser("[email protected]");
        userRepository.save(user);
    }
}

DataSource 構成を定義していないため、アプリケーションは、作成した自動構成を使用して、myDbというMySQLデータベースに接続します。

接続文字列にはcreateDatabaseIfNotExist= true プロパティが含まれているため、データベースが存在する必要はありません。 ただし、ユーザー mysqluser 、または mysql.user プロパティで指定されたユーザー(存在する場合)を作成する必要があります。

アプリケーションログをチェックして、MySQLデータソースが使用されていることを確認できます。

web - 2017-04-12 00:01:33,956 [main] INFO  o.s.j.d.DriverManagerDataSource - Loaded JDBC driver: com.mysql.cj.jdbc.Driver

5. 自動構成クラスの無効化

自動構成のロード除外する場合は、excludeまたはexcludeName属性を持つ@EnableAutoConfigurationアノテーションをに追加できます。構成クラス:

@Configuration
@EnableAutoConfiguration(
  exclude={MySQLAutoconfiguration.class})
public class AutoconfigurationApplication {
    //...
}

特定の自動構成を無効にする別のオプションは、spring.autoconfigure.excludeプロパティを設定することです。

spring.autoconfigure.exclude=com.baeldung.autoconfiguration.MySQLAutoconfiguration

6. 結論

このチュートリアルでは、カスタムSpring Boot自動構成を作成する方法を示しました。 この例の完全なソースコードは、GitHubにあります。

JUnitテストは、 autoconfiguration プロファイルを使用して実行できます: mvn clean install-Pautoconfiguration