Reputation: 1009
I'm trying to get the application properties in the dataSource bean initialization, but I found that the Autowire isn't set yet at that point, so those variables that have @Autowire are still null. For instance:
@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();
}
}
At this point if I try to use the Environment environment, it still null. I was digging about it and found some possible solutions extending the EnvironmentAware and some other things but none of them seems to hit before the dataSource. In the EnvironmentAware it calls the set after passing the dataSource bean.
I was looking into the class SpringApplication, everything seems to happen at ConfigurableApplicationContext run(String... args), in the refreshContext(context), it calls the dataSource bean as part of the Autowire initialization.
Digging a little more, I found that you have some events that happen during the initialization that you can, kind like manually hook to, in the spring.factories, pointing to a class that you want to do something.
I did made a test with it, you do have access to the application and environment variables
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);
}
}
Looks great but, than I tried to use the Autowire to get the env.property back and it still null.
@Value("${test.value}")
private String test;
If I let the code runs, in the EntityManagerFactory entityManagerFactory(), it does have all the Autowire done, so the test.value is there, as also the Environment environment, but at that point is already to late.
Seems to me that I'm missing something here, a configuration to set the order or I have messed up something else instead.
Let's say that this is how things are and this is the order that the beans are being initialized, so in that case, how can I make some use of the spring.factories in a way that I can have access to those variables when the dataSource bean is called?
What I'm doing to be able to read those properties is manually loading the application.properties with
ClassLoader loader = Thread.currentThread().getContextClassLoader();
Properties appProp = new Properties();
try ( InputStream resourceStream = loader.getResourceAsStream("application.properties")) {
appProp.load(resourceStream);
}
It works but, seems wrong.
Thanks in advance.
Upvotes: 0
Views: 458
Reputation: 38777
All dependencies should be injected before any @Bean
methods are called, so that's odd.
If this doesn't work, then you're doing something very odd elsewhere to cause it:
@Bean
public DataSource dataSource(Environment env) {
// ...
}
Upvotes: 1