Spring Boot自动配置顺序

时间:2015-07-29 06:34:38

标签: java spring spring-boot

我想创建一个Spring Boot自动配置类,它(有条件地)创建一个bean A。但挑战是,必须在Spring Boot的默认自动配置类之一中创建另一个bean B之前创建它。 bean B不依赖于A

我的第一次尝试是使用@AutoConfigureBefore。这不符合我的预期,并且由Dave Syer从this comment判断它不应该。

一些背景知识:前面提到的bean A改变了Mongo数据库,这必须在MongoTemplate创建之前发生。

3 个答案:

答案 0 :(得分:3)

事实证明,我想要的是动态地使B的实例依赖于A。这可以通过使用BeanFactoryPostProcessoralter the bean definitions B个bean来实现。

public class DependsOnPostProcessor implements BeanFactoryPostProcessor {

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                beanFactory, B.class, true, false);
        for (String beanName : beanNames) {
            BeanDefinition definition = beanFactory.getBeanDefinition(beanName);
            definition.setDependsOn(StringUtils.addStringToArray(
                    definition.getDependsOn(), "beanNameOfB");
        }
    }

}

这适用于普通的Spring,不需要Spring Boot。要完成自动配置,我需要将DependsOnPostProcessor的bean定义添加到实例化bean A的配置类中。

答案 1 :(得分:0)

Boot 1.3.0中有一个新的注释@AutoConfigureOrder。虽然至少我不清楚这是否仍然与@AutoConfiugreBefore相同。

答案 2 :(得分:0)

请参阅@hzpz的答案,以下是在自动配置Hikari数据源之前创建数据库的示例。

import com.zaxxer.hikari.HikariDataSource;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import javax.annotation.PostConstruct;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;

@Configuration
public class CreateDatabaseConfig {

  @Value("${spring.datasource.url}")
  private String url;
  @Value("${spring.datasource.hikari.username}")
  private String username;
  @Value("${spring.datasource.hikari.password}")
  private String password;
  @Value("${spring.datasource.hikari.catalog}")
  private String catalog;

  @Bean
  public static BeanFactoryPostProcessor dependsOnPostProcessor() {
    return beanFactory -> {
      String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
          beanFactory, HikariDataSource.class, true, false);
      for (String beanName : beanNames) {
        BeanDefinition definition = beanFactory.getBeanDefinition(beanName);
        definition.setDependsOn(StringUtils.addStringToArray(
            definition.getDependsOn(), "createDatabaseConfig"));
      }
    };
  }

  @PostConstruct
  public void init() {
    try (
        Connection connection = DriverManager.getConnection(url, username, password);
        Statement statement = connection.createStatement()
    ) {
      statement.executeUpdate(
          "CREATE DATABASE IF NOT EXISTS `" + catalog
              + "` DEFAULT CHARACTER SET = utf8mb4 COLLATE utf8mb4_unicode_ci;"
      );
    } catch (SQLException e) {
      throw new RuntimeException("Create Database Fail", e);
    }
  }
}

可以使用data.sqlschema.sql完成模式和数据的更多初始化,请参见85. Database Initialization
ps。我尝试在CREATE DATABASE中使用schema.sql,但失败了,上面的示例有效:)