Spring Boot依赖注入异常:子类对象被注入父类变量问题排查
问题描述
尝试实现工厂设计模式,根据传入参数返回不同类的对象:传入指定参数返回父类对象,另一参数返回子类对象。父类继承自抽象类,该抽象类实现了Interface接口。但传入父类对应的参数时,工厂返回的却是子类对象。调试发现,工厂构造函数调用时,父类变量中注入的已是子类对象。尝试使用Lombok的@RequiredArgsConstructor注解但无效果。
环境:Spring Boot 2.3.9.RELEASE、JDK 1.8,使用JUnit测试验证代码。
代码实现
Interface接口
public interface Interface {}
抽象父类
@RequiredArgsConstructor @Component public abstract class AbstractClass implements Interface{}
父类
@Slf4j @Component("ParentClass") public class ParentClass extends AbstractClass {}
子类
@Slf4j @Component("ChildClass") public class ChildClass extends ParentClass {}
工厂类
@Component @Slf4j public class Factory { private final ParentClass parentClass; private final ChildClass childClass; Factory(@Qualifier("ParentClass") ParentClass parentClass, @Qualifier("ChildClass") ChildClass childClass) { this.parentClass = parentClass; this.childClass = childClass; } public Interface getObject(boolean isParent){ if(isParent) return parentClass; else return childClass; } }
JUnit测试类
@RunWith(MockitoJUnitRunner.class) public class FactoryTest { @InjectMocks private Factory factory; @Mock private ParentClass parentClass; @Mock private ChildClass childClass; @Test public void getObjectTest() { assertEquals(parentClass, factory.getObject(true)); } }
问题原因与解决方案
测试环境问题(Mockito注入错误)
你的测试使用MockitoJUnitRunner,当存在ParentClass和ChildClass两个mock时,由于ChildClass是ParentClass的子类,Mockito的@InjectMocks可能会错误地将ChildClass的mock注入到Factory的parentClass字段中(子类类型匹配父类类型),导致测试断言失败。
解决方法:
- 给mock指定名称,并用
@Qualifier匹配注入:
@RunWith(MockitoJUnitRunner.class) public class FactoryTest { @InjectMocks private Factory factory; @Mock @Qualifier("ParentClass") private ParentClass parentClass; @Mock @Qualifier("ChildClass") private ChildClass childClass; @Test public void getObjectTest() { assertEquals(parentClass, factory.getObject(true)); } }
- 或者改用构造函数注入的方式手动创建Factory实例,避免Mockito自动注入的歧义:
@RunWith(MockitoJUnitRunner.class) public class FactoryTest { private Factory factory; @Mock private ParentClass parentClass; @Mock private ChildClass childClass; @Before public void setup() { factory = new Factory(parentClass, childClass); } @Test public void getObjectTest() { assertEquals(parentClass, factory.getObject(true)); } }
实际Spring运行环境问题
如果在实际运行时也出现父类变量注入子类对象的情况,原因是Spring容器中同时存在ParentClass和ChildClass两个bean,而ChildClass是ParentClass的子类,当Spring进行自动装配时,如果@Qualifier未正确生效,可能会注入子类实例。
解决方法:
- 确保
@Qualifier注解的参数与@Component指定的bean名称完全一致(注意大小写)。 - 检查
AbstractClass的@RequiredArgsConstructor是否影响子类构造:由于AbstractClass没有final或@NonNull字段,@RequiredArgsConstructor会生成无参构造函数,子类ParentClass和ChildClass可以正常实例化,这部分无需修改。 - 避免使用
@Primary注解(容易引发其他装配歧义),优先保证@Qualifier的正确使用。
内容的提问来源于stack exchange,提问作者Kashyap jalela
相关产品推荐
相关产品推荐

