I've seen similar questions and tried many variants, came up with what should work but still having a NullPointerException. This is a web application, here's my AppListener's contextInitialized():
AnnotationConfigWebApplicationContext wac = new AnnotationConfigWebApplicationContext();
wac.setServletContext(sc);
wac.setParent(rootContext);
propertySourcesPlaceholderConfigurer = new PropertySourcesPlaceholderConfigurer();
propertySourcesPlaceholderConfigurer.setLocation(new PathResource(_configFile)); // yes it's dynamic
wac.addBeanFactoryPostProcessor(propertySourcesPlaceholderConfigurer);
wac.register(Configuration.class);
sc.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac);
//TODO check if works properly - security. didn't manage to keep it in the same config class
wac.register(SecurityConfiguration.class);
wac.refresh();
here's my config class (Configuration.class):
@Autowired //(used to be @Inject, no difference)
private Environment env;
@Bean
public MessageSource messageSource(){
ReloadableResourceBundleMessageSource ms = new ReloadableResourceBundleMessageSource();
ms.addBasenames(new String[]{
env.getProperty("paths.appConfigDir") + "/i18n/message",
env.getProperty("paths.defaultConfigDir") + "/i18n/message"
});
ms.setDefaultEncoding("UTF-8");
return ms;
}
env is null, thus NPE.
What am I doing wrong?
What is a modern way to do have properties from a file loaded both into placeholders and environment, having properties file name evaluated at startup (basically, taken from another config file)?
What order should be my app context mehtods calls? (Guessing here's my mistake)
Add Let me additionally stress that the properties file name is a variable
Update The correct answer is marked below: don't do weird things or you'll face some gotchas.
Though the answer and the advice is correct, it didn't help me due to other reasons that me as an unexperienced Spring user had no idea that were worth included to the question. Basically, I've got an answer to my question, but I couldn't follow the advice, had to deep debug things and found out the following two items you may consider if you followed my route:
The config class was instantiated too early and thus lacked the Environment injected, because:
1) Don't call your configuration class "Configuration". During the initialization phase Something in Spring Web tries to get the bean called "configuration", sees this class and instantiates it.
2) Move messageSource bean to a parent context, as it is sought early in Spring Web initialization; it seems impossible to query the Environment in the messageSource bean method, there's no Environment yet.
Hope this helps.
Add below mentioned annotation in your Configuration class:
1. @PropertySourceWorking code will be like:
@Configuration @PropertySource("classpath:your-property-file.properties") public class Config { @Autowired private Environment env; @Bean(name="testSource") public MessageSource messageSource(){ ReloadableResourceBundleMessageSource ms = new ReloadableResourceBundleMessageSource(); ms.addBasenames(new String[]{ env.getProperty("paths.appConfigDir") + "/i18n/message", env.getProperty("paths.defaultConfigDir") + "/i18n/message" }); ms.setDefaultEncoding("UTF-8"); return ms; } }
To modify the PropertySource
instances used by the Environment
use an ApplicationContextInitializer
. This allows you to add PropertySource
instances before the ApplicationContext
is actually created.
public class YourApplicationContextInitializer implements ApplicationContextInitializer {
public void initialize(ConfigurableApplicationContext context) {
Resource resource = new PathResource(_configFile);
ConfigurableEnvironment env = context.getEnvironment();
MutablePropertySources mps = env.getPropertySources();
mps.addFirst(new ResourcePropertySource("config-file", resource));
}
}
This class will add your configured PathResource
as the first PropertySource
in the Environment
and will also be used by the, presumably, already available PropertySourcesPlaceholderConfigurer
.
Assuming that you have a WebApplicationInitializer
which extends AbstractAnnotationConfigDispatcherServletInitializer
implement the getRootApplicationContextInitializers
and getServletApplicationContextInitializers
to return an instance of this class.
public class YourWebApplicationInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
// Your other init code here
protected ApplicationContextInitializer<?>[] getServletApplicationContextInitializers() {
return new ApplicationContextInitializer[] { new YourApplicationContextInitializer()};
}
protected ApplicationContextInitializer<?>[] getRootApplicationContextInitializers() {
return new ApplicationContextInitializer[] { new YourApplicationContextInitializer()};
}
}
The getRootApplicationContextInitializers
will add ApplictionContexInitializer
for the context loaded by the ContextLoaderListener
the getServletApplicationContextInitializers
will do the same for the DispatcherServlet
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.