Spring Boot中如何注入接口的所有可能实现实例作为构造器依赖?
问题解决:Spring中注入同一实现类的不同实例到工厂类
场景说明
我有如下工厂类:
@Service class AffectedObjectServiceFactory { private static final Map<String, AffectedObjectService> affectedObjectServiceMap = new HashMap<>(); @Autowired private AffectedObjectServiceFactory(List<AffectedObjectService> services) { for(AffectedObjectService service : services) { String[] supportedSubTypes = service.func1(); for (String subType: supportedSubTypes) { affectedObjectServiceMap.put(subType, service); } } } public static AffectedObjectService getAffectedObject(String type) { AffectedObjectService affectedObjectService = affectedObjectServiceMap.get(type); if(affectedObjectService == null) throw new IllegalArgumentException("Unknown service type: " + type); return affectedObjectService; } }
对应的接口及实现类如下:
interface AffectedObjectService { String[] func1(); // 修正:与工厂类调用逻辑匹配,返回值应为String[] } @Component class AffectedObjectServiceImpl1 implements AffectedObjectService { @Override String[] func1() { //.... } } @Component class AffectedObjectServiceImpl2 implements AffectedObjectService { @Override String[] func1() { //.... } } class AffectedObjectServiceImpl3 implements AffectedObjectService { XYZInterface type; public AffectedObjectServiceImpl3(XYZInterface type) { this.type = type; } @Override String[] func1() { //.... } } interface XYZInterface { String func2(); } @Component class XYZInterfaceImpl1 implements XYZInterface { // 修正:接口实现需用implements而非extends @Override String func2() { // .... } } @Component class XYZInterfaceImpl2 implements XYZInterface { @Override String func2() { // .... } }
问题
AffectedObjectService是一个拥有多个实现类的接口,其中部分实现类的构造器依赖其他接口的实现。如何让AffectedObjectServiceImpl3的两个实例(分别依赖XYZInterfaceImpl1和XYZInterfaceImpl2)都作为依赖注入到工厂类的构造器中?
解决方案
核心思路是让Spring显式创建AffectedObjectServiceImpl3的两个实例,分别绑定不同的XYZInterface实现,再将这两个实例纳入List<AffectedObjectService>的注入集合中。推荐采用以下方式:
方式一:通过配置类手动定义Bean
移除AffectedObjectServiceImpl3上的@Component注解,避免Spring自动生成默认实例,然后通过配置类创建两个指定依赖的实例:
@Configuration public class AffectedObjectConfig { // 创建依赖XYZInterfaceImpl1的实例 @Bean public AffectedObjectService serviceImpl3WithXyz1(XYZInterfaceImpl1 xyzImpl1) { return new AffectedObjectServiceImpl3(xyzImpl1); } // 创建依赖XYZInterfaceImpl2的实例 @Bean public AffectedObjectService serviceImpl3WithXyz2(XYZInterfaceImpl2 xyzImpl2) { return new AffectedObjectServiceImpl3(xyzImpl2); } }
Spring会自动将这两个Bean加入到List<AffectedObjectService>中,工厂类的构造器就能获取到这两个实例。
方式二:结合@Qualifier限定依赖
如果需要更灵活的依赖选择,可以给XYZInterface的实现类添加@Qualifier标记,再在配置类中指定依赖:
- 给
XYZInterface实现类添加限定符:
@Component @Qualifier("xyzImpl1") class XYZInterfaceImpl1 implements XYZInterface { @Override String func2() { // .... } } @Component @Qualifier("xyzImpl2") class XYZInterfaceImpl2 implements XYZInterface { @Override String func2() { // .... } }
- 在配置类中创建实例时指定依赖:
@Configuration public class AffectedObjectConfig { @Bean public AffectedObjectService serviceImpl3WithXyz1(@Qualifier("xyzImpl1") XYZInterface xyzInterface) { return new AffectedObjectServiceImpl3(xyzInterface); } @Bean public AffectedObjectService serviceImpl3WithXyz2(@Qualifier("xyzImpl2") XYZInterface xyzInterface) { return new AffectedObjectServiceImpl3(xyzInterface); } }
关键注意事项
- 必须移除
AffectedObjectServiceImpl3的@Component注解,否则Spring会尝试自动创建一个实例,若存在多个XYZInterface实现会直接导致依赖注入失败。 - 修正原代码中的两处语法错误:
AffectedObjectService接口的func1方法返回值需与工厂类调用逻辑保持一致,改为String[];XYZInterface是接口,其实现类需用implements关键字而非extends。
内容的提问来源于stack exchange,提问作者Noor Ahmad
相关产品推荐
相关产品推荐

