Spring回顾——自动装配模式

Spring 支持五种自动装配模式:

  • byName模式:在使用byName模式进行自动装配时,Spring会尝试用每个属性去上下文中适配同名的bean,例如有一个TestInject bean,该bean中有一个私有属性 OmsGoodsVo 并且 我们在ApplicationContext中也定义了名为 OmsGoodsVo这个bean,那么在TestInject初始化时OmsGoodsVo这个bean将会被自动分配给TestInject中的OmsGoodsVo属性。

  • byType模式:在使用byType模式进行自动装配时,Spring会尝试在Spring上下文中取寻找相同类型的bean去分配给目标bean的对应属性。

  • 构造函数模式:该模式和byType模式有异曲同工之妙,该模式通过bean的构造器进行注入而不是通过setter ,在该模式下Spring总是会尝试进行构造器最大入参的适配,例如TestInjectbean有两个构造器分别是TestInject1(String,Integer) 和TestInject2(String) 如果在ApplicationContext上下文中同时存在一个String bean和 Integer bean,那么Spring总是会去使用TestInject1去进行注入。

  • 默认模式:Spring 将自动在构造函数模式和byType模式之间进行选择,选择的依据是如果bean存在一个默认的无参数构造函数则使用byType模式进行构造,否则用构造函数模式。

  • :不使用任何模式,这是Spring的默认设置


示例

有如下一个简单的配置文件:appliacation_test.xml, 我们将使用如下的bean来尝试不同的装配模式















在上面的配置中可以看见有两个空类 OmsGoodsVo 和 StockAllVo 并且同时命名为omsGoodsVo和stockAllVo ,同时有三个TestInject类来分别进行byTypebyNameconstructor的注入测试,设置lazy-init为true的目的是为了控制日志的打印位置并无其他作用

TestInject类:


/**

* @ClassName TestInject

* @Description 测试注入类

* @Author liuzhibo

* @Date 2019/2/28 11:00 PM

**/

public class TestInject{
 private OmsGoodsVo omsGoodsVoOne;
 private OmsGoodsVo omsGoodsVoTwo;
 private StockAllVo stockAllVo;

 public TestInject() {}
 
 public TestInject(OmsGoodsVo omsGoodsVo){
      System.out.println("单参数构造注入");
 }

 public TestInject(OmsGoodsVo omsGoodsVo,StockAllVo stockAllVo) {
      System.out.println("双参数构造注入");
 }
 
 public void setOmsGoodsVoOne(OmsGoodsVo omsGoodsVoOne) {
      System.out.println("属性装配-》set omsGoodsVoOne");
 }

 public void setOmsGoodsVoTwo(OmsGoodsVo omsGoodsVoTwo) {
      System.out.println("属性装配-》set omsGoodsVoTwo");
 }
 
 public void setStockAllVo(StockAllVo stockAllVo) {
      System.out.println("属性装配-》set stockAllVo");
 }

 public static void main(String[] args) {

   GenericXmlApplicationContext  ctx = new GenericXmlApplicationContext();
   ctx.load("classpath:/application_test.xml");
   ctx.refresh();
   
   TestInjecttestInject = null;
   System.out.println("----------------ByName 测试----------------");
   testInject = (TestInject) ctx.getBean("injectByName");

   System.out.println("----------------ByType 测试----------------");
   testInject = (TestInject) ctx.getBean("injectByType");

   System.out.println("----------------ByConstructor 测试----------------");
   testInject = (TestInject) ctx.getBean("injectByConstructor");
  }
}

在上面这段代码中,可以看到TestInject类拥有三个构造函数和三个私有属性以及对应的setter方法和一个main方法,我们将通过getBean的方式来分别触发byName,byType,byConstructor注入模式。

运行结果:

----------------ByName测试----------------

属性装配-》set stockAllVo

----------------ByType测试----------------

属性装配-》set omsGoodsVoOne

属性装配-》set omsGoodsVoTwo

属性装配-》set stockAllVo

----------------ByConstructor测试----------------

双参数构造注入

可以看到byName模式下只自动注入了stockAllVo,这是符合我们期望的一个结果,因为在TestInject中只有stockAllVo能通过名称在ApplocationContext上下文中找到适配的bean,当使用byType模式时,spring自动装配了TestInject类中的所有三个属性,构造函数注入同样是符合期望的。


Spring自动装配的日常应用

相信大多数人都遇到过 org.springframework.beans.factory.NoSuchBeanDefinitionException或者org.springframework.beans.factory.UnsatisfiedDependencyException 这两个异常,该异常大多数是在通过@Autowired注入bean时Spring在上下文中发现了相同类型的bean从而不知道该如何选择装配导致的,所以,有没有思考过以下问题:

1.为什么@Service通常不会直接打在interface上?

2.@Autowired为什么会有一个@Qualifier 与其适配?@Resource呢?


参考书籍:
《Spring 5 高级编程》第五版

你可能感兴趣的:(Spring回顾——自动装配模式)