Spring无XML配置:如何将不同类实例注入Bean的Map/List?
在纯注解Spring环境中注入Bean到Map/List的方案
嘿,这个问题我熟!在纯注解的Spring环境里,要把不同类的实例注入到Map或List中,还能按名称/实现类精准筛选,Spring本身就提供了灵活的实现方式,我给你分场景拆解:
一、基础场景:同一接口下的自动注入
如果所有目标Bean都实现了同一个接口(比如你提到的I接口),Spring会自动帮你完成批量注入,无需额外配置:
1. 注入到Map<String, I>
Spring会自动将所有实现I接口的Bean注入到Map中:
- Key:Bean的名称(即
@Component指定的value,比如@Component("instanceA")的key就是instanceA;如果没指定,默认是类名首字母小写,比如class A默认名称为a) - Value:对应的Bean实例
示例代码:
// 定义接口 public interface I {} // 实现类1 @Component("instanceA") public class A implements I {} // 实现类2 @Component("instanceB") public class B implements I {} // 目标Bean,注入Map @Component public class TargetBean { // 自动注入所有实现I的Bean到Map @Autowired private Map<String, I> iBeanMap; public void printBeans() { iBeanMap.forEach((name, bean) -> System.out.println(name + ": " + bean.getClass().getSimpleName())); // 输出:instanceA: A; instanceB: B } }
2. 注入到List
同样,Spring会自动收集所有实现I接口的Bean到List中,可通过@Order注解控制顺序:
// 实现类添加@Order指定顺序 @Component("instanceA") @Order(2) public class A implements I {} @Component("instanceB") @Order(1) public class B implements I {} // 目标Bean注入List @Component public class TargetBean { @Autowired private List<I> iBeanList; public void printBeans() { iBeanList.forEach(bean -> System.out.println(bean.getClass().getSimpleName())); // 输出:B; A(按@Order顺序) } }
二、进阶场景:精准筛选特定实例
如果需要只注入指定名称或实现类的Bean,或者Bean没有共同接口,就需要手动控制注入逻辑:
1. 按名称指定注入(通用场景)
通过@Bean方法手动构建Map/List,精准注入指定名称的Bean:
@Configuration public class BeanConfig { // 按名称注入指定Bean到Map @Bean public Map<String, Object> namedBeanMap( @Qualifier("instanceA") A instanceA, @Qualifier("instanceC") C instanceC) { Map<String, Object> map = new HashMap<>(); map.put("instanceA", instanceA); map.put("instanceC", instanceC); return map; } // 按名称注入指定Bean到List @Bean public List<Object> namedBeanList( @Qualifier("instanceA") A instanceA, @Qualifier("instanceB") B instanceB) { return Arrays.asList(instanceA, instanceB); } } // 目标Bean中注入自定义的Map/List @Component public class TargetBean { @Autowired private Map<String, Object> namedBeanMap; @Autowired private List<Object> namedBeanList; }
2. 按实现类指定注入
如果需要按类型筛选(比如只注入A、C类的实例),可以借助ApplicationContext来获取指定类型的Bean:
@Configuration public class BeanConfig { @Autowired private ApplicationContext context; // 按类型筛选Bean到Map @Bean public Map<String, Object> typedBeanMap() { Map<String, Object> map = new HashMap<>(); // 获取所有A类型的Bean map.putAll(context.getBeansOfType(A.class)); // 获取所有C类型的Bean map.putAll(context.getBeansOfType(C.class)); return map; } }
3. 自定义注解筛选(灵活场景)
如果需要更灵活的筛选规则,可以自定义一个注解标记需要注入的Bean,再通过代码筛选:
// 自定义注解 @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface IncludeInMap {} // 标记需要注入的Bean @Component("instanceA") @IncludeInMap public class A implements I {} @Component("instanceC") @IncludeInMap public class C {} // 配置类中筛选带注解的Bean @Configuration public class BeanConfig { @Autowired private ApplicationContext context; @Bean public Map<String, Object> annotatedBeanMap() { return BeanFactoryUtils.beansOfTypeIncludingAncestors(context, Object.class, true, false) .entrySet().stream() .filter(entry -> entry.getValue().getClass().isAnnotationPresent(IncludeInMap.class)) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); } }
三、注意事项
- 如果Bean没有指定名称(
@Component未传value),默认名称是类名首字母小写(比如class MyBean默认名称为myBean) - 当注入List时,
@Order注解可以控制Bean的排序顺序 - 非同一接口的Bean注入Map时,建议用
Map<String, Object>,再配合筛选逻辑避免注入无关Bean
内容的提问来源于stack exchange,提问作者MS13
相关产品推荐
相关产品推荐

