首页 > 解决方案 > 设置自动装配后运行 dataSource bean

问题描述

我试图在 dataSource bean 初始化中获取应用程序属性,但我发现此时尚未设置 Autowire,因此具有 @Autowire 的那些变量仍然为空。例如:

@Configuration
@EnableTransactionManagement
public class Config{

    @Autowired
    private Environment environment;

    @Bean
    public DataSource dataSource() {
        DataSourceBuilder builder = DataSourceBuilder.create();
   
        builder.driverClassName("org.h2.Driver");
        builder.url("jdbc:h2:mem:test");
        builder.username("someUser");
        builder.password("somePass");
    
        return builder.build();
    }

    @Bean
    public EntityManagerFactory entityManagerFactory() {
        LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();
        //...
        return emf.getObject();
    }
}

此时如果我尝试使用Environment 环境,它仍然为空。我正在研究它,发现一些可能的解决方案扩展了EnvironmentAware和其他一些东西,但它们似乎都没有在dataSource之前出现。在EnvironmentAware中,它在传递dataSource bean后调用集合。

我正在研究SpringApplication 类,一切似乎都发生在ConfigurableApplicationContext run(String... args)中,在refreshContext(context)中,它调用dataSource bean 作为 Autowire 初始化的一部分。

再深入一点,我发现你有一些在初始化期间发生的事件,你可以在spring.factories中手动挂钩,指向你想要做某事的类。

我确实用它做了一个测试,你确实可以访问应用程序环境变量

public class EnvironmentProcessor implements EnvironmentPostProcessor {

    @Override
    public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {           
        final var propertySources = environment.getPropertySources();
        PropertySource<?> property = new MapPropertySource("customProperty",
                Collections.<String, Object>singletonMap("test.value", "worked as intended"));
        propertySources.addLast(property);
    }

}

看起来不错,但是,我尝试使用 Autowire 来获取 env.property 并且它仍然为空。

@Value("${test.value}")
private String test;

如果我让代码运行,在EntityManagerFactory entityManagerFactory()中,它确实完成了所有 Autowire,所以test.value和Environment environment都在那里,但那时已经为时已晚。

在我看来,我在这里遗漏了一些东西,设置订单的配置,或者我搞砸了其他东西。

假设事情就是这样,这是初始化 bean 的顺序,所以在这种情况下,我怎样才能以某种方式使用 spring.factories,以便在dataSource时可以访问这些变量豆叫什么?

为了能够读取这些属性,我正在做的是手动加载 application.properties

    ClassLoader loader = Thread.currentThread().getContextClassLoader();
    Properties appProp = new Properties();
    try ( InputStream resourceStream = loader.getResourceAsStream("application.properties")) {
        appProp.load(resourceStream);
    }

它有效,但似乎是错误的。

提前致谢。

标签: javaspring-boot

解决方案


应该在@Bean调用任何方法之前注入所有依赖项,所以这很奇怪。

如果这不起作用,那么你在其他地方做了一些非常奇怪的事情来导致它:

@Bean
public DataSource dataSource(Environment env) {
   // ...
}

推荐阅读