新增抽象类后@Autowired字段为null,触发NullPointerException
问题描述
原有可正常运行的代码:
@Component public class MessageUtil { @Autowired @Qualifier("processMessages") private ReloadableConfig config; public String createMessage() { return config.getPropertyStr("message.simple.signature"); } }
对应的processMessages Bean定义:
<bean id="processMessages" class="com.company.framework.resources.ReloadableConfig"> <property name="basename" value="classpath:com/company/aaa/bbb/domain/service/processMessages"/> <property name="defaultEncoding" value="UTF-8"/> <property name="cacheSeconds" value="60"/> </bean>
之后创建了新类:
public abstract class MessageBuilder { @Autowired @Qualifier("processMessages") protected ReloadableConfig config; public abstract String createMessage(); } @Component public class SimpleMessageBuilder extends MessageBuilder { private String template; private void setTemplate() { template = config.getPropertyStr("message.simple.signature"); } @Override public String createMessage() { setTemplate(); return template; } }
现在调用SimpleMessageBuilder.createMessage()时触发NullPointerException,原因是setTemplate()方法里的config为null,请问这段新代码问题出在哪?
问题分析与修复方案
核心问题
Spring的依赖注入只作用于被容器管理的实例化Bean,而抽象类无法被实例化,所以MessageBuilder里的@Autowired注解根本不会被Spring处理。子类SimpleMessageBuilder继承的config字段自然就是null,调用方法时就会触发空指针。
两种修复方式
方式一:把抽象类纳入Spring容器(不推荐)
给抽象类MessageBuilder加上@Component注解,让Spring管理它,这样抽象类的字段会被注入,子类继承后就能正常使用:
@Component public abstract class MessageBuilder { @Autowired @Qualifier("processMessages") protected ReloadableConfig config; public abstract String createMessage(); }
这种方式虽然能解决问题,但抽象类本身不需要被实例化,强行加@Component不符合设计初衷,不推荐。
方式二:在子类中注入依赖(推荐)
直接在子类SimpleMessageBuilder里处理依赖注入,避免依赖抽象类的无效注解。推荐用构造方法注入,这是Spring的最佳实践,能确保实例化时依赖就被初始化:
public abstract class MessageBuilder { protected ReloadableConfig config; public abstract String createMessage(); } @Component public class SimpleMessageBuilder extends MessageBuilder { private String template; @Autowired public SimpleMessageBuilder(@Qualifier("processMessages") ReloadableConfig config) { this.config = config; } private void setTemplate() { template = config.getPropertyStr("message.simple.signature"); } @Override public String createMessage() { setTemplate(); return template; } }
如果你习惯字段注入,也可以把@Autowired和@Qualifier直接加在子类的config字段上,但构造注入更利于单元测试,也能明确展示类的依赖关系。
内容的提问来源于stack exchange,提问作者l0r3nz4cc10
相关产品推荐
相关产品推荐

