8.依赖注入之自动注入(autowire)详解

Spring系列第8篇,在此也感谢各位一路的支持,请大家帮忙点个再看并转发到朋友圈让更多的朋友一起学习,感激不尽!

本文内容

  • 手动注入的不足
  • Class.isAssignableFrom方法介绍
  • 3种自动注入方式详解及案例
    • 按名称自动注入
    • 按类型自动注入
    • 按构造器进行自动注入
  • 按类型自动注入某种类型的所有bean给List和Map(重点)
  • autowire=default介绍
  • 总结
  • 案例源码

手动注入的不足

上篇文章中介绍了依赖注入中的手动注入,所谓手动注入是指在xml中采用硬编码的方式来配置注入的对象,比如通过构造器注入或者set方法注入,这些注入的方式都存在不足,比如下面代码:

 
  1. public class A{
  2. private B b;
  3. private C c;
  4. private D d;
  5. private E e;
  6. ....
  7. private N n;
  8. //上面每个private属性的get和set方法
  9. }

使用spring容器来管理,xml配置如下:

 
  1. <bean class="b" class="B"/>
  2. <bean class="c" class="C"/>
  3. <bean class="d" class="D"/>
  4. <bean class="e" class="E"/>
  5. <bean class="a" class="A">
  6. <property name="b" ref="b"/>
  7. <property name="c" ref="c"/>
  8. <property name="d" ref="d"/>
  9. <property name="e" ref="e"/>
  10. ...
  11. </bean>

上面的注入存在的问题:

  • 如果需要注入的对象比较多,比如A类中有几十个属性,那么上面的property属性是不是需要写几十个,此时配置文件代码量暴增
  • 如果A类中新增或者删除了一些依赖,还需要手动去调整bean xml中的依赖配置信息,否则会报错
  • 总的来说就是不利于维护和扩展

为了解决上面这些问题,spring为我们提供了更强大的功能:自动注入

在介绍自动注入之前需要先介绍一些基础知识。

Class.isAssignableFrom方法

用法

isAssignableFrom是Class类中的一个方法,看一下这个方法的定义:

 
  1. public native boolean isAssignableFrom(Class<?> cls)

用法如下:

 
  1. c1.isAssignableFrom(c2)

用来判断c2和c1是否相等,或者c2是否是c1的子类。

案例

 
  1. @Test
  2. public void isAssignableFrom(){
  3. System.out.println(Object.class.isAssignableFrom(Integer.class)); //true
  4. System.out.println(Object.class.isAssignableFrom(int.class)); //false
  5. System.out.println(Object.class.isAssignableFrom(List.class)); //true
  6. System.out.println(Collection.class.isAssignableFrom(List.class)); //true
  7. System.out.println(List.class.isAssignableFrom(Collection.class)); //false
  8. }

自动注入

自动注入是采用约定大约配置的方式来实现的,程序和spring容器之间约定好,遵守某一种都认同的规则,来实现自动注入。

xml中可以在bean元素中通过autowire属性来设置自动注入的方式:

 
  1. <bean id="" class="" autowire="byType|byName|constructor|default" />
  • byteName:按照名称进行注入
  • byType:按类型进行注入
  • constructor:按照构造方法进行注入
  • default:默认注入方式

下面我们详解每种注入方式的用法。

按照名称进行注入(byName)

用法

autowire设置为byName

 
  1. <bean id="" class="X类" autowire="byName"/>

spring容器会按照set属性的名称去容器中查找同名的bean对象,然后将查找到的对象通过set方法注入到对应的bean中,未找到对应名称的bean对象则set方法不进行注入

需要注入的set属性的名称和被注入的bean的名称必须一致。

来看看案例吧。

案例

DiByName.java
 
  1. package com.javacode2018.lesson001.demo6;
  2. /**
  3. * 按照名称自动注入
  4. */
  5. public class DiAutowireByName {
  6. public static class Service1 { //@1
  7. private String desc;
  8. public String getDesc() {
  9. return desc;
  10. }
  11. public void setDesc(String desc) {
  12. this.desc = desc;
  13. }
  14. @Override
  15. public String toString() {
  16. return "Service1{" +
  17. "desc='" + desc + '\'' +
  18. '}';
  19. }
  20. }
  21. public static class Service2 { //@1
  22. private String desc;
  23. public String getDesc() {
  24. return desc;
  25. }
  26. public void setDesc(String desc) {
  27. this.desc = desc;
  28. }
  29. @Override
  30. public String toString() {
  31. return "Service2{" +
  32. "desc='" + desc + '\'' +
  33. '}';
  34. }
  35. }
  36. private Service1 service1;//@3
  37. private Service2 service2;//@4
  38. public Service1 getService1() {
  39. return service1;
  40. }
  41. public void setService1(Service1 service1) {
  42. System.out.println("setService1->" + service1);
  43. this.service1 = service1;
  44. }
  45. public Service2 getService2() {
  46. return service2;
  47. }
  48. public void setService2(Service2 service2) {
  49. System.out.println("setService2->" + service2);
  50. this.service2 = service2;
  51. }
  52. @Override
  53. public String toString() {
  54. return "DiAutowireByName{" +
  55. "service1=" + service1 +
  56. ", service2=" + service2 +
  57. '}';
  58. }
  59. }

这个类中有2个属性,名称为:

  • service1
  • service2

这两个属性都有对应的set方法。

下面我们在bean xml中定义2个和这2个属性同名的bean,然后使用按照名称进行自动注入。

diAutowireByName.xml
 
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans
  5. http://www.springframework.org/schema/beans/spring-beans-4.3.xsd">
  6. <bean id="service1" class="com.javacode2018.lesson001.demo6.DiAutowireByName$Service1">
  7. <property name="desc" value="service1"/>
  8. </bean>
  9. <bean id="service2" class="com.javacode2018.lesson001.demo6.DiAutowireByName$Service2">
  10. <property name="desc" value="service2"/>
  11. </bean>
  12. <bean id="service2-1" class="com.javacode2018.lesson001.demo6.DiAutowireByName$Service2">
  13. <property name="desc" value="service2-1"/>
  14. </bean>
  15. <!-- autowire:byName 配置按照name进行自动注入 -->
  16. <bean id="diAutowireByName1" class="com.javacode2018.lesson001.demo6.DiAutowireByName" autowire="byName"/>
  17. <!-- 当配置了自动注入,还可以使用手动的方式自动注入进行覆盖,手动的优先级更高一些 -->
  18. <bean id="diAutowireByName2" class="com.javacode2018.lesson001.demo6.DiAutowireByName" autowire="byName">
  19. <property name="service2" ref="service2-1"/>
  20. </bean>
  21. </beans>

上面注释认真看一下。

@1:定义了一个名称为service1的bean

@2:定义了一个名称为service2的bean

@3:定义diAutowireByName需要将autowire的值置为byName,表示按名称进行自动注入。

spring容器创建diAutowireByName对应的bean时,会遍历DiAutowireByName类中的所有set方法,然后得到set对应的属性名称列表:{“service1”,”service2”},然后遍历这属性列表,在容器中查找和属性同名的bean对象,然后调用属性对应的set方法,将bean对象注入进去

测试用例
 
  1. package com.javacode2018.lesson001.demo6;
  2. import com.javacode2018.lesson001.demo5.IocUtils;
  3. import org.junit.Test;
  4. import org.springframework.context.support.ClassPathXmlApplicationContext;
  5. import java.util.ArrayList;
  6. import java.util.Collection;
  7. import java.util.List;
  8. /**
  9. * 公众号:路人甲Java,工作10年的前阿里P7分享Java、算法、数据库方面的技术干货!坚信用技术改变命运,让家人过上更体面的生活!
  10. * xml中自动注入配置案例
  11. */
  12. public class DiAutowireTest {
  13. /**
  14. * 按照名称进行注入
  15. */
  16. @Test
  17. public void diAutowireByName() {
  18. String beanXml = "classpath:/com/javacode2018/lesson001/demo6/diAutowireByName.xml";
  19. ClassPathXmlApplicationContext context = IocUtils.context(beanXml);
  20. System.out.println(context.getBean("diAutowireByName"));
  21. }
  22. }
效果

运行diAutowireByName输出:

 
  1. setService1->Service1{desc='service1'}
  2. setService2->Service2{desc='service2'}
  3. setService2->Service2{desc='service2-1'}
  4. setService1->Service1{desc='service1'}
  5. DiAutowireByName{service1=Service1{desc='service1'}, service2=Service2{desc='service2'}}
  6. DiAutowireByName{service1=Service1{desc='service1'}, service2=Service2{desc='service2-1'}}

优缺点

按名称进行注入的时候,要求名称和set属性的名称必须同名,相对于硬编码的方式注入,确实节省了不少代码。

按照类型进行自动注入

用法

autowire设置为byType

 
  1. <bean id="" class="X类" autowire="byType"/>

spring容器会遍历x类中所有的set方法,会在容器中查找和set参数类型相同的bean对象,将其通过set方法进行注入,未找到对应类型的bean对象则set方法不进行注入。

需要注入的set属性的类型和被注入的bean的类型需要满足isAssignableFrom关系。

按照类型自动装配的时候,如果按照类型找到了多个符合条件的bean,系统会报错。

set方法的参数如果是下面的类型或者下面类型的数组的时候,这个set方法会被跳过注入:

Object,Boolean,boolean,Byte,byte,Character,char,Double,double,Float,float,Integer,int,Long,Short,shot,Enum,CharSequence,Number,Date,java.time.temporal.Temporal,java.net.URI,java.net.URI,java.util.Locale,java.lang.Class

来看看案例吧。

案例

DiByType.java
 
  1. package com.javacode2018.lesson001.demo6;
  2. /**
  3. * 按照类型自动注入
  4. */
  5. public class DiAutowireByType {
  6. public static class Service1 {
  7. private String desc;
  8. public String getDesc() {
  9. return desc;
  10. }
  11. public void setDesc(String desc) {
  12. this.desc = desc;
  13. }
  14. @Override
  15. public String toString() {
  16. return "Service1{" +
  17. "desc='" + desc + '\'' +
  18. '}';
  19. }
  20. }
  21. public static class Service2 {
  22. private String desc;
  23. public String getDesc() {
  24. return desc;
  25. }
  26. public void setDesc(String desc) {
  27. this.desc = desc;
  28. }
  29. @Override
  30. public String toString() {
  31. return "Service2{" +
  32. "desc='" + desc + '\'' +
  33. '}';
  34. }
  35. }
  36. private Service1 service1;
  37. private Service2 service2;
  38. public Service1 getService1() {
  39. return service1;
  40. }
  41. public void setService1(Service1 service1) {
  42. System.out.println("setService1->" + service1); //@1
  43. this.service1 = service1;
  44. }
  45. public Service2 getService2() {
  46. return service2;
  47. }
  48. public void setService2(Service2 service2) {
  49. System.out.println("setService2->" + service2); //@2
  50. this.service2 = service2;
  51. }
  52. @Override
  53. public String toString() {
  54. return "DiByType{" +
  55. "service1=" + service1 +
  56. ", service2=" + service2 +
  57. '}';
  58. }
  59. }

DiAutowireByType类中有2个set方法分别来注入Service1和Service2,两个set方法中都输出了一行文字,一会执行的时候可以通过这个输出可以看出set方法是否被调用了。

diAutowireByName.xml
 
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans
  5. http://www.springframework.org/schema/beans/spring-beans-4.3.xsd">
  6. <bean class="com.javacode2018.lesson001.demo6.DiAutowireByType$Service1">
  7. <property name="desc" value="service1"/>
  8. </bean>
  9. <bean class="com.javacode2018.lesson001.demo6.DiAutowireByType$Service2">
  10. <property name="desc" value="service2"/>
  11. </bean>
  12. <!-- autowire:byType 配置按照set参数类型进行自动注入 -->
  13. <bean id="diAutowireByType1" class="com.javacode2018.lesson001.demo6.DiAutowireByType" autowire="byType"/>
  14. </beans>

上面定义了3个bean,前2个bean并没有指定名称

第3个bean的autowire为byType表示按类型进行注入,会按照set方法的参数类型进行注入。

测试用例

DiAutowireTest类中添加一个方法

 
  1. /**
  2. * 按照set方法参数类型进行注入
  3. */
  4. @Test
  5. public void diAutowireByType() {
  6. String beanXml = "classpath:/com/javacode2018/lesson001/demo6/diAutowireByType.xml";
  7. ClassPathXmlApplicationContext context = IocUtils.context(beanXml);
  8. System.out.println(context.getBean("diAutowireByType1"));
  9. }
效果

运行diAutowireByType输出:

 
  1. setService1->Service1{desc='service1'}
  2. setService2->Service2{desc='service2'}
  3. DiByType{service1=Service1{desc='service1'}, service2=Service2{desc='service2'}}

优缺点

相对于手动注入,节省了不少代码,新增或者删除属性,只需要增减对应的set方法就可以了,更容易扩展了。

注入类型匹配的所有bean(重点)

按照类型注入还有2中比较牛逼的用法

  • 一个容器中满足某种类型的bean可以有很多个,将容器中某种类型中的所有bean,通过set方法注入给一个java.util.List<需要注入的Bean的类型或者其父类型或者其接口>对象
  • 将容器中某种类型中的所有bean,通过set方法注入给一个java.util.Map<String,需要注入的Bean的类型或者其父类型或者其接口>对象

来看个案例就懂了。

案例

DiAutowireByTypeExtend.java
 
  1. package com.javacode2018.lesson001.demo6;
  2. import java.util.List;
  3. import java.util.Map;
  4. /**
  5. * 满足条件的bean注入到集合中(重点)
  6. */
  7. public class DiAutowireByTypeExtend {
  8. //定义了一个接口
  9. public interface IService1 {
  10. }
  11. public static class BaseServie {
  12. private String desc;
  13. public String getDesc() {
  14. return desc;
  15. }
  16. public void setDesc(String desc) {
  17. this.desc = desc;
  18. }
  19. @Override
  20. public String toString() {
  21. return "BaseServie{" +
  22. "desc='" + desc + '\'' +
  23. '}';
  24. }
  25. }
  26. //Service1实现了IService1接口
  27. public static class Service1 extends BaseServie implements IService1 {
  28. }
  29. //Service1实现了IService1接口
  30. public static class Service2 extends BaseServie implements IService1 {
  31. }
  32. private List<IService1> serviceList;//@1
  33. private List<BaseServie> baseServieList;//@2
  34. private Map<String, IService1> service1Map;//@3
  35. private Map<String, BaseServie> baseServieMap;//@4
  36. public List<IService1> getServiceList() {
  37. return serviceList;
  38. }
  39. public void setServiceList(List<IService1> serviceList) {//@5
  40. this.serviceList = serviceList;
  41. }
  42. public List<BaseServie> getBaseServieList() {
  43. return baseServieList;
  44. }
  45. public void setBaseServieList(List<BaseServie> baseServieList) {//@6
  46. this.baseServieList = baseServieList;
  47. }
  48. public Map<String, IService1> getService1Map() {
  49. return service1Map;
  50. }
  51. public void setService1Map(Map<String, IService1> service1Map) {//@7
  52. this.service1Map = service1Map;
  53. }
  54. public Map<String, BaseServie> getBaseServieMap() {
  55. return baseServieMap;
  56. }
  57. public void setBaseServieMap(Map<String, BaseServie> baseServieMap) {//@8
  58. this.baseServieMap = baseServieMap;
  59. }
  60. @Override
  61. public String toString() { //9
  62. return "DiAutowireByTypeExtend{" +
  63. "serviceList=" + serviceList +
  64. ", baseServieList=" + baseServieList +
  65. ", service1Map=" + service1Map +
  66. ", baseServieMap=" + baseServieMap +
  67. '}';
  68. }
  69. }

@1,@2,@3,@4:定义了4个属性,都是泛型类型的,都有对应的set方法。

@5:参数类型是List<BaseServie>,这个集合集合中元素的类型是BaseServie,spring会找到容器中所有满足BaseServie.isAssignableFrom(bean的类型)的bean列表,将其通过@5的set方法进行注入。

@6:同@5的代码

@7:这个参数类型是一个map了,map的key是string类型,value是IService1类型,spring容器会将所有满足IService1类型的bean找到,按照name->bean对象这种方式丢到一个map中,然后调用@7的set方法进行注入,最后注入的这个map就是bean的名称和bean对象进行映射的一个map对象。

@8:同@7的代码

@9:重写了toString方法,输出的时候好看一些

测试用例

DiAutowireTest新增一个方法:

 
  1. /**
  2. * 按照类型注入集合
  3. */
  4. @Test
  5. public void diAutowireByTypeExtend() {
  6. String beanXml = "classpath:/com/javacode2018/lesson001/demo6/diAutowireByTypeExtend.xml";
  7. ClassPathXmlApplicationContext context = IocUtils.context(beanXml);
  8. //从容器中获取DiAutowireByTypeExtend
  9. DiAutowireByTypeExtend diAutowireByTypeExtend = context.getBean(DiAutowireByTypeExtend.class);
  10. //输出diAutowireByTypeExtend中的属性看一下
  11. System.out.println("serviceList:" + diAutowireByTypeExtend.getServiceList());
  12. System.out.println("baseServieList:" + diAutowireByTypeExtend.getBaseServieList());
  13. System.out.println("service1Map:" + diAutowireByTypeExtend.getService1Map());
  14. System.out.println("baseServieMap:" + diAutowireByTypeExtend.getBaseServieMap());
  15. }
效果

运行diAutowireByTypeExtend输出:

 
  1. serviceList:[BaseServie{desc='service1-1'}, BaseServie{desc='service1-2'}, BaseServie{desc='service2-1'}]
  2. baseServieList:[BaseServie{desc='service1-1'}, BaseServie{desc='service1-2'}, BaseServie{desc='service2-1'}]
  3. service1Map:{service1-1=BaseServie{desc='service1-1'}, service1-2=BaseServie{desc='service1-2'}, service2-1=BaseServie{desc='service2-1'}}
  4. baseServieMap:{service1-1=BaseServie{desc='service1-1'}, service1-2=BaseServie{desc='service1-2'}, service2-1=BaseServie{desc='service2-1'}}

下面我们来介绍另外一种自动注入方式。

按照构造函数进行自动注入

用法

autowire设置为constructor

 
  1. <bean id="" class="X类" autowire="constructor"/>

spring会找到x类中所有的构造方法(一个类可能有多个构造方法),然后将这些构造方法进行排序(先按修饰符进行排序,public的在前面,其他的在后面,如果修饰符一样的,会按照构造函数参数数量倒叙,也就是采用贪婪的模式进行匹配,spring容器会尽量多注入一些需要的对象)得到一个构造函数列表,会轮询这个构造器列表,判断当前构造器所有参数是否在容器中都可以找到匹配的bean对象,如果可以找到就使用这个构造器进行注入,如果不能找到,那么就会跳过这个构造器,继续采用同样的方式匹配下一个构造器,直到找到一个合适的为止。

来看看案例吧。

案例

DiAutowireByConstructor.java
 
  1. package com.javacode2018.lesson001.demo6;
  2. /**
  3. * 构造函数的方式进行自动注入
  4. */
  5. public class DiAutowireByConstructor {
  6. public static class BaseServie {
  7. private String desc;
  8. public String getDesc() {
  9. return desc;
  10. }
  11. public void setDesc(String desc) {
  12. this.desc = desc;
  13. }
  14. @Override
  15. public String toString() {
  16. return "BaseServie{" +
  17. "desc='" + desc + '\'' +
  18. '}';
  19. }
  20. }
  21. //Service1实现了IService1接口
  22. public static class Service1 extends BaseServie {
  23. }
  24. //Service1实现了IService1接口
  25. public static class Service2 extends BaseServie {
  26. }
  27. private Service1 service1;
  28. private Service2 service2;
  29. public DiAutowireByConstructor() { //@0
  30. }
  31. public DiAutowireByConstructor(Service1 service1) { //@1
  32. System.out.println("DiAutowireByConstructor(Service1 service1)");
  33. this.service1 = service1;
  34. }
  35. public DiAutowireByConstructor(Service1 service1, Service2 service2) { //@2
  36. System.out.println("DiAutowireByConstructor(Service1 service1, Service2 service2)");
  37. this.service1 = service1;
  38. this.service2 = service2;
  39. }
  40. public Service1 getService1() {
  41. return service1;
  42. }
  43. public void setService1(Service1 service1) {
  44. this.service1 = service1;
  45. }
  46. public Service2 getService2() {
  47. return service2;
  48. }
  49. public void setService2(Service2 service2) {
  50. this.service2 = service2;
  51. }
  52. @Override
  53. public String toString() {
  54. return "DiAutowireByConstructor{" +
  55. "service1=" + service1 +
  56. ", service2=" + service2 +
  57. '}';
  58. }
  59. }

@1:1个参数的构造函数

@2:2个参数的构造函数

2个有参构造函数第一行都打印了一段文字,一会在输出中可以看到代码是调用了那个构造函数创建对象。

diAutowireByConstructor.xml
 
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans
  5. http://www.springframework.org/schema/beans/spring-beans-4.3.xsd">
  6. <bean class="com.javacode2018.lesson001.demo6.DiAutowireByConstructor$Service1">
  7. <property name="desc" value="service1"/>
  8. </bean>
  9. <bean id="diAutowireByConstructor" class="com.javacode2018.lesson001.demo6.DiAutowireByConstructor"
  10. autowire="constructor"/>
  11. </beans>
测试用例

DiAutowireTest新增一个方法

 
  1. /**
  2. * 构造函数的方式进行自动注入
  3. */
  4. @Test
  5. public void diAutowireByConstructor() {
  6. String beanXml = "classpath:/com/javacode2018/lesson001/demo6/diAutowireByConstructor.xml";
  7. ClassPathXmlApplicationContext context = IocUtils.context(beanXml);
  8. System.out.println(context.getBean("diAutowireByConstructor"));
  9. }
效果

运行diAutowireByConstructor输出:

 
  1. DiAutowireByConstructor(Service1 service1)
  2. DiAutowireByConstructor{service1=BaseServie{desc='service1'}, service2=null}

从输出中可以看到调用的是DiAutowireByConstructor类中的第一个构造函数注入了service1 bean。

构造函数匹配采用贪婪匹配,多个构造函数结合容器找到一个合适的构造函数,最匹配的就是第一个有参构造函数,而第二个有参构造函数的第二个参数在spring容器中找不到匹配的bean对象,所以被跳过了。

我们在diAutowireByConstructor.xml加入Service2的配置:

 
  1. <bean class="com.javacode2018.lesson001.demo6.DiAutowireByConstructor$Service2">
  2. <property name="desc" value="service2"/>
  3. </bean>

再来运行一下diAutowireByConstructor输出:

 
  1. DiAutowireByConstructor(Service1 service1, Service2 service2)
  2. DiAutowireByConstructor{service1=BaseServie{desc='service1'}, service2=BaseServie{desc='service2'}}

此时可以看到第二个有参构造函数被调用了,满足了贪婪方式的注入原则,最大限度的注入所有依赖的对象。

autowire=default

用法

bean xml的根元素为beans,注意根元素有个default-autowire属性,这个属性可选值有(no|byName|byType|constructor|default),这个属性可以批量设置当前文件中所有bean的自动注入的方式,bean元素中如果省略了autowire属性,那么会取default-autowire的值作为其autowire的值,而每个bean元素还可以单独设置自己的autowire覆盖default-autowire的配置,如下:

 
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans
  5. http://www.springframework.org/schema/beans/spring-beans-4.3.xsd"
  6. default-autowire="byName">
  7. </beans>

案例

diAutowireByDefault.xml
 
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans
  5. http://www.springframework.org/schema/beans/spring-beans-4.3.xsd"
  6. default-autowire="byName"> //@1
  7. <bean id="service1" class="com.javacode2018.lesson001.demo6.DiAutowireByName$Service1">
  8. <property name="desc" value="service1"/>
  9. </bean>
  10. <bean id="service2" class="com.javacode2018.lesson001.demo6.DiAutowireByName$Service2">
  11. <property name="desc" value="service2"/>
  12. </bean>
  13. <bean id="service2-1" class="com.javacode2018.lesson001.demo6.DiAutowireByName$Service2">
  14. <property name="desc" value="service2-1"/>
  15. </bean>
  16. <!-- autowire:default,会采用beans中的default-autowire指定的配置 -->
  17. <bean id="diAutowireByDefault1" class="com.javacode2018.lesson001.demo6.DiAutowireByName" autowire="default"/> //@2
  18. <!-- autowire:default,会采用beans中的default-autowire指定的配置,还可以使用手动的方式自动注入进行覆盖,手动的优先级更高一些 -->
  19. <bean id="diAutowireByDefault2" class="com.javacode2018.lesson001.demo6.DiAutowireByName" autowire="default"> //@3
  20. <property name="service2" ref="service2-1"/>
  21. </bean>
  22. </beans>

注意上面的@1配置的default-autowire=”byName”,表示全局默认的自动注入方式是:按名称注入

@2和@3的autowire=default,那么注入方式会取default-autowire的值。

测试用例

DiAutowireTest中新增一个方法

 
  1. /**
  2. * autowire=default
  3. */
  4. @Test
  5. public void diAutowireByDefault() {
  6. String beanXml = "classpath:/com/javacode2018/lesson001/demo6/diAutowireByDefault.xml";
  7. ClassPathXmlApplicationContext context = IocUtils.context(beanXml);
  8. System.out.println(context.getBean("diAutowireByDefault1"));
  9. System.out.println(context.getBean("diAutowireByDefault2"));
  10. }
效果

运行diAutowireByDefault输出

 
  1. setService1->Service1{desc='service1'}
  2. setService2->Service2{desc='service2'}
  3. setService2->Service2{desc='service2-1'}
  4. setService1->Service1{desc='service1'}
  5. DiAutowireByName{service1=Service1{desc='service1'}, service2=Service2{desc='service2'}}
  6. DiAutowireByName{service1=Service1{desc='service1'}, service2=Service2{desc='service2-1'}}

总结

  • xml中手动注入存在的不足之处,可以通过自动注入的方式来解决,本文介绍了3中自动注入:通过名称自动注入、通过类型自动注入、通过构造器自动注入
  • 按类型注入中有个比较重要的是注入匹配类型所有的bean,可以将某种类型所有的bean注入给一个List对象,可以将某种类型的所有bean按照bean名称->bean对象的映射方式注入给一个Map对象,这种用法比较重要,用途比较大,要掌握
  • spring中还有其他自动注入的方式,用起来会更爽,后面的文章中我们会详细介绍。

案例源码

 
  1. 链接:https://pan.baidu.com/s/1p6rcfKOeWQIVkuhVybzZmQ
  2. 提取码:zr99
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值