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

为何@Autowired注入的ApplicationContext为null?Spring Boot 2.7.6问题

Spring Boot 2.7.6中ApplicationContext在@Bean方法中为null的问题排查

问题背景

使用Spring Boot 2.7.6,启动类中通过@Autowired注入的ApplicationContext在getISEARequestHandler()方法中始终为null,该方法创建的ISEARequestHandler被Rest控制器自动注入。同时项目中存在自定义的SEABeanDefinitionRegistryPostProcessor,通过DeferredImportSelector导入。

启动类核心代码:

@SpringBootApplication
@MapperScan(basePackages = "fwx.apps.ebidding.**.mappers", annotationClass = fwx.sea.impl.mybatis.annotations.SEAMapper.class)
@Import(SEAPostProcessorSelector.class)
public class EbiddingApplication {

    @Autowired
    private ApplicationContext springContext;

    @Bean
    public ISEARequestHandler getISEARequestHandler() {
        return new MybatisSEARequestHandler(springContext.getBean(MybatisSEAContext.class));
    }

    // 其他@Bean方法...
}

原因分析

  1. 启动类字段注入时机滞后
    Spring初始化时会先实例化启动类,再执行其中的@Bean方法,而@Autowired字段的注入是在启动类实例化之后的依赖注入阶段完成的。这就导致执行getISEARequestHandler()等@Bean方法时,springContext还未被赋值,因此为null。

  2. PostProcessor提前触发bean实例化
    SEABeanDefinitionRegistryPostProcessor实现了BeanDefinitionRegistryPostProcessor,其postProcessBeanFactory()方法在bean定义注册完成后、bean实例化前执行。方法中调用beanFactory.getBean(ISEAContext.class)会提前触发ISEAContext的实例化,此时启动类的springContext还未完成注入,进而导致ISEAContext及其依赖的ISEARequestHandler都拿到null的ApplicationContext。

解决方案

方案1:使用参数注入替代字段注入(推荐)

Spring支持在@Bean方法中直接声明依赖参数,框架会自动注入对应的bean,无需手动通过ApplicationContext.getBean()获取。这种方式更符合Spring最佳实践,也避免了字段注入的时机问题。

修改启动类中的@Bean方法:

@SpringBootApplication
@MapperScan(basePackages = "fwx.apps.ebidding.**.mappers", annotationClass = fwx.sea.impl.mybatis.annotations.SEAMapper.class)
@Import(SEAPostProcessorSelector.class)
public class EbiddingApplication {

    // 移除@Autowired的springContext字段

    @Bean
    public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
        SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
        factoryBean.setDataSource(dataSource);
        return factoryBean.getObject();
    }

    @Bean
    public SqlSessionTemplate sqlSession(SqlSessionFactory sqlSessionFactory) throws Exception {
        return new SqlSessionTemplate(sqlSessionFactory);
    }

    @Bean
    public MybatisSEAContext getSEAContext(ApplicationContext springContext) {
        return new SpringMybatisSEAContext(springContext);
    }

    @Bean
    public ISEARequestHandler getISEARequestHandler(MybatisSEAContext seaContext) {
        return new MybatisSEARequestHandler(seaContext);
    }

    // 其他@Bean方法...
}

方案2:实现ApplicationContextAware接口

让启动类实现ApplicationContextAware接口,通过重写setApplicationContext()方法获取容器实例,该方法会在ApplicationContext初始化完成后被调用,确保springContext已赋值。

@SpringBootApplication
@MapperScan(basePackages = "fwx.apps.ebidding.**.mappers", annotationClass = fwx.sea.impl.mybatis.annotations.SEAMapper.class)
@Import(SEAPostProcessorSelector.class)
public class EbiddingApplication implements ApplicationContextAware {

    private ApplicationContext springContext;

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

    // 原@Bean方法可保留,此时springContext已被正确赋值
}

调整PostProcessor逻辑,避免提前实例化bean

SEABeanDefinitionRegistryPostProcessor中调用beanFactory.getBean()会提前触发实例化,建议修改逻辑:

  • 对于SEAListener的注册,可改用BeanPostProcessor在bean实例化完成后处理;
  • 对于Mapper的映射注册,仅在PostProcessor中保存映射元数据,等ISEAContext初始化完成后再批量设置,避免提前获取bean实例。

示例:改用BeanPostProcessor处理监听器注册

@Component
public class SEABeanPostProcessor implements BeanPostProcessor {

    private Logger log = LoggerFactory.getLogger(getClass());

    @Autowired
    private ISEAContext seaContext;

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        SEAListener listenerAnnotation = bean.getClass().getAnnotation(SEAListener.class);
        if (listenerAnnotation != null) {
            String locator = listenerAnnotation.locator();
            log.info("注册SEA监听器:[" + bean.getClass().getName() + "] ==> " + locator);
            seaContext.addListener(locator, bean.getClass().getName());
        }
        return bean;
    }
}

总结

核心问题是启动类字段注入时机晚于@Bean方法执行,以及自定义PostProcessor提前触发bean实例化导致依赖链异常。通过参数注入或ApplicationContextAware可解决ApplicationContext为null的问题,同时调整PostProcessor逻辑能避免提前实例化带来的连锁问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 22:22:02