Spring能否注入依赖带有相同限定符的限定类?
当然可以!你的核心需求是:让ServiceB中注入的ServiceWithDependency实例,内部自动装配的是@Qualifier("backup")的DepA,同时又不想额外新建一个ServiceWithDependency的子类或副本对吧?
下面给你两种实用的解决方案,都是不用新增类的:
方案一:显式创建带限定符的ServiceWithDependency Bean(最直接)
问题出在你当前的代码里,Spring自动创建的ServiceWithDependency实例(假设你给这个类加了@Component注解)会默认注入@Primary的PrimaryA,而你在ServiceB里用@Qualifier("backup")找ServiceWithDependency时,Spring根本找不到标记了这个限定符的实例。
所以我们可以在配置类里手动创建一个绑定了backup版DepA的ServiceWithDependency Bean,并给它加上@Qualifier("backup"),这样就能和ServiceB的注入匹配上:
@Configuration public class BeanInjection { @Bean("backup") public DepA getBackUpA() { return new BackUp(); } @Bean @Primary public DepA getA() { return new PrimaryA(); } // 新增:创建带backup依赖的ServiceWithDependency实例 @Bean @Qualifier("backup") // 标记这个bean,让ServiceB能找到它 public ServiceWithDependency backupServiceWithDependency( @Qualifier("backup") DepA backupDepA // 注入backup版的DepA ) { // 强烈建议给ServiceWithDependency加构造函数注入(Spring官方推荐) return new ServiceWithDependency(backupDepA); } }
同时,把ServiceWithDependency改成构造注入的方式(替换原来的字段注入),这样依赖更清晰,也避免手动设置字段的麻烦:
public class ServiceWithDependency { private final DepA depA; // 构造函数注入,Spring会自动装配对应的DepA实例 @Autowired public ServiceWithDependency(DepA depA) { this.depA = depA; } }
这样ServiceB里的注入就会精准拿到这个绑定了backup版DepA的ServiceWithDependency实例,完美符合你的需求。
方案二:使用自定义限定符注解(更优雅的进阶方式)
如果你觉得到处写@Qualifier("backup")不够优雅,可以自定义一个限定符注解,比如@Backup:
@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Qualifier public @interface Backup { }
然后修改配置类和注入点:
@Configuration public class BeanInjection { @Bean @Backup // 用自定义注解标记backup版DepA public DepA getBackUpA() { return new BackUp(); } @Bean @Primary public DepA getA() { return new PrimaryA(); } @Bean @Backup // 标记这个ServiceWithDependency实例 public ServiceWithDependency backupServiceWithDependency( @Backup DepA backupDepA // 注入标记了@Backup的DepA ) { return new ServiceWithDependency(backupDepA); } }
ServiceB里的注入也改成用自定义注解:
public class ServiceB { @Autowired @Backup // 用自定义注解匹配 private ServiceWithDependency ser; }
这种方式可读性更好,也避免了字符串字面量写错的问题,适合大型项目使用。
为什么你原来的代码不行?
再帮你理清楚根源:你给ServiceB里的ServiceWithDependency加了@Qualifier("backup"),但Spring容器中没有任何一个ServiceWithDependency实例被标记为backup——默认的ServiceWithDependency实例(如果是@Component扫描的)没有这个限定符,而你只给DepA的备份实例加了@Qualifier("backup"),两者没有关联,所以Spring找不到匹配的Bean。
备注:内容来源于stack exchange,提问作者icefire112233

