You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring中@Autowired注入PropertySourcesPlaceholderConfigurer子类为空的原因

问题描述

自定义类PropertyManager继承自PropertySourcesPlaceholderConfigurer,标注了@Component与@PropertySource注解。类中通过@Autowired注入ContextHolder实例时始终返回null,但调用ContextHolder的静态方法却能正常获取上下文。猜测是因为PropertySourcesPlaceholderConfigurer属于BeanFactoryPostProcessor,初始化时ContextHolder实例尚未创建,想请教为何@Autowired注入失效。

相关代码:

/* 这个Bean注入后始终为null */
@Component
public class ContextHolder implements ApplicationContextAware, ServletContextAware {
    
    private static ApplicationContext springContext;
    private static ServletContext servletContext;
    
    @Override
    public void setServletContext(ServletContext servletContext) {
        this.servletContext = servletContext;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.springContext = applicationContext;
    }
    
    public static ApplicationContext getSpringContext() {
        return springContext;
    }

    public static ServletContext getServletContext() {
        return servletContext;
    }
}


@Component
@PropertySource("classpath:appProps/globals-${spring.profiles.active}.properties")
public class PropertyManager extends PropertySourcesPlaceholderConfigurer {
    @Autowired
    ContextHolder contextHolder; // 此处注入始终为null
    
    public String get(String key) {
        // 抛出空指针异常,因为contextHolder为null
        // 但ContextHolder.getSpringContext()静态调用正常,想知道@Autowired为何失效
        return contextHolder.getSpringContext().getEnvironment().getProperty(key);
    }
}
问题原因与解决方案

核心原因

你的猜测完全正确,PropertySourcesPlaceholderConfigurer是BeanFactoryPostProcessor的实现类,它的初始化时机远早于普通Bean:

  1. Spring容器启动时,会先实例化所有BeanFactoryPostProcessor类型的Bean,并立即执行它们的postProcessBeanFactory方法,这个阶段还未开始普通Bean的实例化和依赖注入流程。
  2. ContextHolder是普通的@Component Bean,它的实例化、依赖注入以及ApplicationContextAware接口的回调,都发生在BeanFactoryPostProcessor执行完成之后。
  3. 所以当Spring创建PropertyManager实例时,ContextHolder还没被实例化,自然无法完成@Autowired注入,导致contextHolder为null。

而静态方法能正常工作,是因为ContextHolder的静态变量springContext是在Spring后续处理普通Bean时,通过setApplicationContext方法赋值的,此时PropertyManager虽然已经存在,但静态变量是全局的,后续赋值后就能通过静态方法访问到。

解决方案

方案1:直接使用静态方法(最简单)

既然静态调用已经能正常工作,直接在PropertyManager中使用ContextHolder.getSpringContext()即可,无需依赖实例注入:

@Component
@PropertySource("classpath:appProps/globals-${spring.profiles.active}.properties")
public class PropertyManager extends PropertySourcesPlaceholderConfigurer {
    
    public String get(String key) {
        return ContextHolder.getSpringContext().getEnvironment().getProperty(key);
    }
}

方案2:避免继承PropertySourcesPlaceholderConfigurer

如果一定要用实例注入,可以调整设计:不要让PropertyManager继承PropertySourcesPlaceholderConfigurer,而是单独用一个类处理属性加载,PropertyManager作为普通Bean来使用:

// 单独配置属性源
@Configuration
@PropertySource("classpath:appProps/globals-${spring.profiles.active}.properties")
public class PropertyConfig {}

// 普通Bean,正常注入依赖
@Component
public class PropertyManager {
    @Autowired
    private ContextHolder contextHolder;
    
    public String get(String key) {
        return contextHolder.getSpringContext().getEnvironment().getProperty(key);
    }
}

方案3:通过BeanFactoryPostProcessor的回调获取上下文

如果必须继承PropertySourcesPlaceholderConfigurer,可以重写processProperties方法,直接从属性解析器中获取环境对象,不需要依赖ContextHolder:

@Component
@PropertySource("classpath:appProps/globals-${spring.profiles.active}.properties")
public class PropertyManager extends PropertySourcesPlaceholderConfigurer {
    private ConfigurableEnvironment environment;

    @Override
    protected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess, ConfigurablePropertyResolver propertyResolver) throws BeansException {
        this.environment = (ConfigurableEnvironment) propertyResolver;
        super.processProperties(beanFactoryToProcess, propertyResolver);
    }

    public String get(String key) {
        return environment.getProperty(key);
    }
}

内容的提问来源于stack exchange,提问作者jijonbo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 17:56:05