以编程方式添加占位符配置程序时,Spring上下文环境为null

时间:2017-12-19 14:12:51

标签: java spring

我已经看过类似的问题并尝试了很多变体,想出了应该工作但仍然有NullPointerException的东西。这是一个Web应用程序,这是我的AppListener的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();

这是我的配置类(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为null,因此是NPE。

我做错了什么?

什么是现代方法,将文件中的属性加载到占位符和环境中,在启动时评估属性文件名(基本上,从另一个配置文件中获取)?

我的应用程序上下文mehtods调用应该是什么顺序? (猜猜这是我的错误)

添加 让我另外强调属性文件名是变量

更新 正确的答案标记如下:不要做奇怪的事情,否则你将面临一些陷阱。

虽然答案和建议是正确的,但由于其他原因,我作为一个没有经验的Spring用户不知道值得包含在问题中,这对我没有帮助。基本上,我已经得到了我的问题的答案,但我无法遵循建议,不得不深入调试事情,并发现如果你遵循我的路线你可能会考虑以下两个项目:

配置类过早实例化,因此缺少注入的环境,因为:

1)不要将配置类称为“配置”。在初始化阶段,Spring Web中的某些东西尝试获取名为“configuration”的bean,看到这个类并实例化它。

2)将messageSource bean移动到父上下文,因为它是在Spring Web初始化中尽早寻找的;在messageSource bean方法中查询环境似乎是不可能的,还没有环境。

希望这有帮助。

2 个答案:

答案 0 :(得分:0)

在Configuration类中添加以下提到的注释:

1. @PropertySource

工作代码如下:

@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;
    }
}

答案 1 :(得分:0)

要修改PropertySource使用的Environment个实例,请使用ApplicationContextInitializer。这允许您在实际创建PropertySource之前添加ApplicationContext个实例。

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));
    }
}

此课程会将您已配置的PathResource添加为PropertySource中的第一个Environment,并且也可能已被可用的PropertySourcesPlaceholderConfigurer使用。

假设您有WebApplicationInitializer扩展AbstractAnnotationConfigDispatcherServletInitializer实现getRootApplicationContextInitializersgetServletApplicationContextInitializers以返回此类的实例。

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()};
    } 

}

getRootApplicationContextInitializers将为ApplictionContexInitializer ContextLoaderListener加载的上下文添加getServletApplicationContextInitializers DispatcherServlet将对id subject date 1 MCA 2/5/2010 1 BSC SCIENCE 5/8/1997 2 BTECH 8/9/1999 3 BTECH 8/6/2000 3 MTECH 6/7/2014 执行相同操作。