在Spring Boot项目中,如何把某些接口实现类的Bean注入到到Arrays, java.util.Collection, and java.util.Map中,方便应用的时候直接读取?其实,Spring是支持这种基于接口实现类的直接注入的——使用注解@Autowired。
软件环境
-
java version 13.0.1
- IntelliJ IDEA 2019.3.2 (Ultimate Edition)
- Spring Boot 2.3.0.RELEASE
举例说明
新增一个没有方法的接口BeanInterface:
/** * 定义bean接口
*/
public interface BeanInterface {
void doSth(String sth);
}
创建两个实现类:
package com.east7.service.impl; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; /** * order:把实现类排序输出 只适合List * * @author 20190265 * @date 2020/7/8 21:27 */ @Order(2) @Component public class BeanImplOne implements BeanInterface { @Override public void doSth(String sth) { System.out.println(String.format("BeanImplOne:%s", sth)); } } ===========我是分割线============= package com.east7.service.impl; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; /** * * @author 20190265 * @date 2020/7/8 21:29 */ @Order(1) @Component("beanImplTwoAlias") //指定bean的名称 public class BeanImplTwo implements BeanInterface { @Override public void doSth(String sth) { System.out.println(String.format("BeanImplTwo:%s", sth)); } }
下面新增一个类BeanInvoker,主要测试@Autowired注解能否把我们预期的Bean注入Map和List类型的变量中。
package com.east7.service.impl; import com.east7.service.BeanInterface; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import javax.annotation.Resource; import java.util.List; import java.util.Map; /** * @author Wiener * @date 2020/7/7 21:32 */ @Component public class BeanInvoker { @Autowired(required = false) private List<BeanInterface> list; @Autowired private Map<String, BeanInterface> map; /** * @Autowired默认为byType的 所以有两个相同类型的bean; * 如果不使用 @Resource 指定具体的bean就会抛出异常 * private BeanInterface beaninterface; */ @Resource(name = "beanImplOne") private BeanInterface beaninterface; public void say() { System.out.println("list..."); list.forEach(bean -> { System.out.println(bean.getClass().getName()); }); System.out.println("map..."); map.forEach((key, value) -> { System.out.println(key + ":" + value.getClass().getName()); }); System.out.println("-------------------------"); System.out.println(beaninterface.getClass().getName()); beaninterface.doSth("在打印此信息!"); beaninterface = map.get("beanImplTwoAlias"); beaninterface.doSth("当前方法的实现类,表明切换实现类成功!"); } }
修改Spring Boot 启动类的main函数:
/**
* @author Wiener
*/
@SpringBootApplication
public class East7Application {
public static void main(String[] args) {
ApplicationContext act = SpringApplication.run(East7Application.class, args);
BeanInvoker invoker = (BeanInvoker) act.getBean("beanInvoker");
invoker.say();
}
}
以断点模式运行main函数,在断点视图中可以看到接口的两个实现类已经全部注入到属性list和map中,而且map里面的key默认设置为两个实现类的类名,如下图所示:
放开断点后,控制台打印结果如下:
list...
com.east7.service.impl.BeanImplTwo
com.east7.service.impl.BeanImplOne
map...
beanImplOne:com.east7.service.impl.BeanImplOne
beanImplTwoAlias:com.east7.service.impl.BeanImplTwo
-------------------------
com.east7.service.impl.BeanImplOne
BeanImplOne:在打印此信息!
BeanImplTwo:当前方法的实现类,表明切换实现类成功!
关于list中的Bean,Spring是怎么排序的?在实现类中加入@Order(value) 注解即可指定Bean的序列,值越小优先级越高,就尽早被初始化和放入list。
关于两个集合变量中的Bean,为什么只有BeanInterface类型的?Spring把容器中所有与集合中元素类型相同的Bean提取出来,构造成对应集合,注入到目标Bean(如变量map)中。