Spring中@Autowired注入为空但ApplicationContextAware可用问题排查
让我们一步步拆解你遇到的问题——明明两个单例Bean单独运行正常,但三种注入方式都失败,只能靠ApplicationContextAware临时解决,大概率是上下文范围、组件扫描或者Hessian服务配置的问题,下面是具体的排查和解决步骤:
1. 先确认组件扫描是否覆盖了所有目标Bean
你的XML配置和SpringBoot启动类都指定了扫描hu.bme.sch.qpa包,但要确保:
PersistenceBean和HelloWorldBean的实际包路径都在hu.bme.sch.qpa或者它的子包下- 如果其中一个Bean在这个范围之外,Spring的组件扫描会直接忽略它,自然无法注入。
可以通过打印容器内的所有Bean名称来验证:在PersistenceBean的setApplicationContext方法里添加这段代码,查看目标Bean是否存在:
@Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.context = applicationContext; // 打印所有注册的Bean名称 for (String beanName : applicationContext.getBeanDefinitionNames()) { System.out.println("Registered Bean: " + beanName); } }
如果输出里找不到HelloWorld.NAME对应的Bean,就需要调整component-scan的base-package,把目标Bean所在的包加进去。
2. 检查Hessian服务的上下文归属
因为你的Bean是作为HessianServiceExporter的基础,很容易出现跨上下文注入的问题:
- Web应用中常存在两个Spring上下文:根上下文(由
ContextLoaderListener或SpringBoot启动类加载)和Servlet上下文(比如DispatcherServlet或Hessian的专属Servlet加载) - 如果Hessian的
ServiceExporter配置在Servlet上下文里,而你的业务Bean(PersistenceBean、HelloWorldBean)在根上下文,虽然Servlet上下文可以访问根上下文的Bean,但如果注入逻辑写反了,或者上下文没有正确设置父子关系,就会导致注入失败。
解决办法:
- 确保所有相关Bean(包括Hessian的Exporter)都在同一个ApplicationContext里
- 如果必须分上下文,要把业务Bean放在根上下文,Hessian Exporter放在Servlet上下文(子上下文可以自动访问父上下文的Bean)
3. 验证注入代码的正确性
你提到三种注入方式都失败,先确认你的注入代码是否符合Spring的规范:
字段注入
@Service(Persistence.NAME) public class PersistenceBean implements Persistence { // 如果HelloWorld有多个实现,必须加@Qualifier指定Bean名称 @Autowired @Qualifier(HelloWorld.NAME) private HelloWorld helloWorld; @Override public User getUser() { User user = new User(); user.setEmail(helloWorld.getText()); return user; } }
构造器注入(推荐方式)
@Service(Persistence.NAME) public class PersistenceBean implements Persistence { private final HelloWorld helloWorld; // 构造器注入不需要@Autowired(Spring 4.3+),如果有多个实现同样加@Qualifier public PersistenceBean(@Qualifier(HelloWorld.NAME) HelloWorld helloWorld) { this.helloWorld = helloWorld; } @Override public User getUser() { User user = new User(); user.setEmail(helloWorld.getText()); return user; } }
方法注入
@Service(Persistence.NAME) public class PersistenceBean implements Persistence { private HelloWorld helloWorld; @Autowired @Qualifier(HelloWorld.NAME) public void setHelloWorld(HelloWorld helloWorld) { this.helloWorld = helloWorld; } @Override public User getUser() { User user = new User(); user.setEmail(helloWorld.getText()); return user; } }
重点:如果HelloWorld接口有多个实现类,必须用@Qualifier指定你要注入的Bean名称(也就是HelloWorld.NAME),否则Spring会因为歧义无法完成注入。
4. 排查上下文重复加载问题
你的CoreStarter是SpringBootServletInitializer,它已经负责加载Spring上下文,如果你的web.xml里还配置了ContextLoaderListener,会导致两个独立的ApplicationContext被创建:
- 你的Bean会被实例化两次,注入的可能是另一个上下文里未完成依赖注入的实例,导致字段为空。
解决办法:
- 检查web.xml(如果存在),移除
ContextLoaderListener的配置,统一用SpringBoot的方式加载上下文。
5. 排除自定义BeanPostProcessor的干扰
虽然你的配置里只有Spring官方的persistenceExceptionTranslationPostProcessor,但如果有其他自定义的BeanPostProcessor,可能干扰了依赖注入的流程。可以暂时移除自定义的BeanPostProcessor,测试是否能正常注入。
按照上面的步骤逐一排查,应该能找到问题所在。
内容的提问来源于stack exchange,提问作者László Stahorszki

