spring自动注入依赖

2022/01/08 spring专题 共 18372 字,约 53 分钟
闷骚的程序员

1. spring手动注入依赖的不足

之前已经知道,spring提供了手动注入依赖的方式:通过构造器注入和通过setter属性注入。
手动注入依赖需要我们显式编写bean xml配置,即采用硬编码的方式进行依赖注入。
手动注入依赖的方式存在如下不足:

public class A{
    private B b;
    private C c;
    private D d;
    private E e;
    ...
    private N n;
    //上面每个private属性的set和get方法
}

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

<bean id="b" class="B"/>
<bean id="c" class="C"/>
<bean id="d" class="D"/>
<bean id="e" class="E"/>
...
<bean id="a" class="A">
    <property name="b" ref="b"/>
    <property name="c" ref="c"/>
    <property name="d" ref="d"/>
    <property name="e" ref="e"/>
    ...
</bean>

上面手动注入存在的问题:

  1. 如果需要注入的对象比较多,比如A类中有几十个属性的话,那么上面的property标签就得写几十个,测试配置文件代码量暴增。
  2. 如果A类中新增或者删除了一些依赖,还需要手动调整bean xml中的依赖配置信息,否则会报错。
  3. 像这种手动注入的配置不利于维护和扩展。
    为了解决上述问题,spring为我们提供了更加强大的功能:自动注入。

2. 自动注入的基础知识

class.isAssignableFrom()

我们在学习反射时,知道Class类中有一个isAssignableFrom方法,该方法定义如下:

public native boolean isAssignableFrom(Class<?> cls);

它是一个本地方法,用法如下:

c1.isAssignableFrom(c2);

判断c1对象描述的类或者接口,是否与c2描述的类或者接口相同,或者是c2描述的类或接口的父类或者父接口。
即用来表示”c1是不是c2的爸爸”。
spring底层按照属性类型自动注入时,就是通过该方法来判断两个对象的类型是否是兼容的。

System.out.println(Object.class.isAssignableFrom(Integer.class)); //true
System.out.println(Object.class.isAssignableFrom(int.class)); //false
System.out.println(Object.class.isAssignableFrom(List.class)); //true
System.out.println(Collection.class.isAssignableFrom(List.class)); //true
System.out.println(List.class.isAssignableFrom(Collection.class)); //false

3. spring依赖注入之自动注入

自动注入是采用约定大于配置的方式实现的。程序和spring之间都约定好,遵守某种双方都认可的规则,来实现自动注入。
xml中可以在bean元素中通过autowire属性来设置自动注入的方式:

<bean id="" class="" autowire="byName|byType|constructor|default|no"/>
  1. byName:按照名称进行注入
  2. byType:按照类型进行注入
  3. constructor:按照构造方法进行注入
  4. default:默认注入方式
  5. no:不使用自动注入,相当于不配置autowire属性
其中byName和byType都是基于setter属性注入,要求目标bean存在setter方法;constructor基于构造器注入,要求目标bean存在对应参数的构造方法。

3.1 按照名称进行注入(byName)

用法:
autowire设置为byName:

<bean id="bean名称" class="类权限定名" autowire="byName"/>

原理分析:
spring容器会按照set属性的名称(注意是setter方法后面跟的名称,首字母自动会转换为小写,而不是属性名称)去容器中查找同名的bean对象,然后将查找到的对象注入到对应的bean中。
未找到对应名称的bean对象,则不会调用set方法进行注入。
需要注入的setter属性的名称和被注入的bean的名称必须保持一致。

tips:spring在反射setter方法时,实际上是将setter方法后面的名称首字母转换为小写,然后和容器中的所有bean进行比对,而不是直接反射属性名称。
比如:

Class A{
    private String name;
    public void setTest(String name){
        this.name = name;
    }
}

这个时候要注入的bean的名称就是test,而不是name。
当然一般的bean,setter和getter方法都是直接按照属性名称去命名的,这种案例只是为了说明它反射的是setter方法而不是属性。

AutowireModel:

package com.zeh.main.pojo;

public class AutowireModel {
    private Service1 service1;
    private Service2 service2;
    public void setService1_test(Service1 service1) {
        System.out.println(String.format("setService1_test->%s", service1));
        this.service1 = service1;
    }
    public void setService2_test(Service2 service2) {
        System.out.println(String.format("setService2_test->%s", service2));
        this.service2 = service2;
    }
    @Override
    public String toString() {
        return "AutowireModel{" + "service1 = '" + this.service1 + "',service2 = '" + this.service2 + "'}";
    }
}
class Service1 {
    private String desc;
    public String getDesc() {
        return desc;
    }
    public void setDesc(String desc) {
        this.desc = desc;
    }
    @Override
    public String toString() {
        return "Service1{" + "desc = '" + this.getDesc() + "'}";
    }
}
class Service2 {
    private String desc;
    public String getDesc() {
        return desc;
    }
    public void setDesc(String desc) {
        this.desc = desc;
    }
    @Override
    public String toString() {
        return "Service2{" + "desc = '" + this.getDesc() + "'}";
    }
}

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

service1
service2

它们有对应的set方法,名称为:

setService1_test
setService2_test

bean xml:

<bean id="service1_test" class="com.zeh.main.pojo.Service1">
    <property name="desc" value="我是service1_test" />
</bean>
<bean id="service2_test" class="com.zeh.main.pojo.Service2">
    <property name="desc" value="我是service2_test" />
</bean>
<bean id="autowireBean" class="com.zeh.main.pojo.AutowireModel" autowire="byName" />

注意上面的bean名称,service1_test和service2_test,是和需要注入的属性的setter方法后面的名称一致,而不是和属性名称一致。

测试:

package com.zeh.main.controller;
import com.zeh.main.util.IocUtil;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AutowireController {
    public static void main(String[] args) {
        String beanXml = "classpath:/spring/applicationContext.xml";
        ClassPathXmlApplicationContext context = IocUtil.getIocContext(beanXml);
        System.out.println(String.format("bean is %s", context.getBean("autowireBean")));
    }
}

测试结果:

setService1_test->Service1{desc = '我是service1_test'}
setService2_test->Service2{desc = '我是service2_test'}
bean is AutowireModel{service1 = 'Service1{desc = '我是service1_test'}',service2 = 'Service2{desc = '我是service2_test'}'}

如果将bean xml中的service1_test和service2_test换成对应的属性名称,即service1和service2的话,执行结果如下:

bean is AutowireModel{service1 = 'null',service2 = 'null'}

发现如果spring在容器中找不到和要注入的setter方法后面的名称匹配的bean,则不会反射调用对应的setter方法去注入属性,因为没有找到和setter方法匹配的bean。

案例原理分析:

  1. AutowireModel中定义了名称为service1和service2的两个属性。
  2. 这两个属性有对应的setter方法,分别是setService1_test和setService2_test。
  3. xml bean中定义了名称为service1_test的bean和名称为service2_test的bean。
  4. xml bean中定义autowireBean时,需要将autowire属性设置为byName,表示按照setter名称进行自动注入。
  5. spring容器创建autowireBean对应的bean时,会遍历AutowireModel类中所有的setter方法,然后得到setter方法对应的属性列表:{“setService1_test”,”setService2_test”},然后遍历该setter属性列表,在容器中查找和该列表中同名的bean对象,找到了则调用对应的set方法,将bean对象注入进去;找不到则不调用。

优缺点:
按名称进行依赖注入的时候,要求需要注入的setter方法的属性名称必须和被注入的bean名称保持一致,相比较于硬编码的方式,节省了不少配置。

3.2 按照类型进行注入(byType)

用法:
autowire设置为byType:

<bean id="bean名称" class="类权限定名" autowire="byType"/>

原理分析:
spring容器会遍历目标类中所有set方法,会在容器中查找和set方法参数类型相同的bean对象(byName是查找和setXXX后面的XXX相同的bean),将其通过set方法进行注入,找不到对应类型的bean对象,则不调用对应的set方法进行注入。
需要注入的set属性的参数类型和被注入的bean的类型需要满足isAssignableFrom的关系,即,set属性参数的类型应该和被注入的bean的类型相同,或者是其父类型。
按照类型进行自动注入时,如果按照类型找到了多个符合条件的bean对象,则系统会报错。
set方法的的参数如果是下面的类型或者下面类型的数组时,这个set方法会被跳过注入:

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

bean xml:

<bean id="service1-1-1" class="com.zeh.main.pojo.Service1">
    <property name="desc" value="我是service1_test" />
</bean>
<bean id="service2-2-2" class="com.zeh.main.pojo.Service2">
    <property name="desc" value="我是service2_test" />
</bean>
<bean id="autowireBean" class="com.zeh.main.pojo.AutowireModel" autowire="byType" />

注意上面的bean名称,专门将bean名称修改成service1-1-1和service2-2-2,表示此时的注入和setter属性名称完全无关。

测试结果:

setService1_test->Service1{desc = '我是service1_test'}
setService2_test->Service2{desc = '我是service2_test'}
bean is AutowireModel{service1 = 'Service1{desc = '我是service1_test'}',service2 = 'Service2{desc = '我是service2_test'}'}

如果上面的bean xml中对于同一个类型的bean有多个满足Service.isAssignableFrom(bean)的bean实例,则通过byType完成自动注入会报错。

bean xml对于Service2类型注册多个实例:

<bean id="service1-1-1" class="com.zeh.main.pojo.Service1">
    <property name="desc" value="我是service1_test" />
</bean>
<bean id="service2-2-2" class="com.zeh.main.pojo.Service2">
    <property name="desc" value="我是service2_test" />
</bean>
<bean id="service2-2-3" class="com.zeh.main.pojo.Service2">
    <property name="desc" value="我是service2_test" />
</bean>
<bean id="autowireBean" class="com.zeh.main.pojo.AutowireModel" autowire="byType" />

上面的bean xml中对于Service2类型添加了一个新的bean实例,即service2-2-3。
此时容器中,Service2类型的实例有两个:service2-2-2、service2-2-3。
spring容器启动后会遍历AutowireModel类中的所有setter方法,得到需要注入的实例类型列表,本案例中是{“com.zeh.main.pojo.Service1”,”com.zeh.main.pojo.Service2”};
根据得到的类型列表,分别去spring容器中去找和对应类型存在isAssignableFrom关系的bean实例。
比如,本案例中会先从spring容器中查找所有满足 com.zeh.main.pojo.Service1.class.sAssignableFrom(目标bean) 关系的目标bean,找到了就注入;
然后再查找满足 com.zeh.main.pojo.Service2.class.sAssignableFrom(目标bean) 关系的目标bean,找到了就注入,如果找到了多个,spring不知道该注入哪个,就会抛出异常。
很明显,spring从容器中找到了两个Service2的实例,service2-2-2和service2-2-3,因此spring报错了。

报错如下:

Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.zeh.main.pojo.Service2' available: expected single matching bean but found 2: service2-2-2,service2-2-3

上面报错也就是说,spring对于com.zeh.main.pojo.Service2类型,没有找到唯一的bean定义。
这个问题后面文章会给出解决方案。

案例原理分析:

  1. 遍历AutowireModel中所有setter方法,找到其参数类型对应的列表集合,比如案例中就是{“Service1”,”Service2”};
  2. 根据对应的类型列表,挨个在spring容器中查找和其满足isAssignableFrom关系的bean实例,即列表中的类型.isAssignableFrom(spring容器中的实例);
  3. 如果在spring容器中找到了多个实例bean,则报错;否则找到对应的bean实例和对应的setter方法,调用setter方法将实例bean注入进去。

优缺点:
相比较手动注入,节省了代码开发,新增或者删除属性,只需要增减对应的set方法即可,更容易进行扩展。

3.3 byType扩展:注入类型匹配的所有bean(重点)

按照类型自动完成依赖注入,还有2种比较牛逼的用法如下:

  1. 一个spring容器中满足某种类型的bean可以存在很多个(比如上面Service2的bean就存在两个),将容器中某种类型的所有bean,通过set方法注入给一个java.util.List<需要注入的bean类型或者其父类型或者其接口>对象。
  2. 将容器中某种类型的所有bean,通过set方法注入给一个java.util.Map<需要注入的bean类型或者其父类型或者其接口>对象。

AutowireModel:

package com.zeh.main.pojo;
import java.util.List;
import java.util.Map;

public class AutowireModel {
    private List<Service> serviceList;
    private Map<String, Service> serviceMap;
    public List<Service> getServiceList() {
        return serviceList;
    }
    public void setServiceList(List<Service> serviceList) {
        this.serviceList = serviceList;
    }
    public Map<String, Service> getServiceMap() {
        return serviceMap;
    }
    public void setServiceMap(Map<String, Service> serviceMap) {
        this.serviceMap = serviceMap;
    }
    @Override
    public String toString() {
        return "AutowireModel{" + "serviceList = '" + this.serviceList + "',serviceMap = '" + this.serviceMap + "'}";
    }
}
interface Service {
}
class Service1 implements Service {
    private String desc;
    public String getDesc() {
        return desc;
    }
    public void setDesc(String desc) {
        this.desc = desc;
    }
    @Override
    public String toString() {
        return "Service1{" + "desc = '" + this.getDesc() + "'}";
    }
}
class Service2 implements Service {
    private String desc;
    public String getDesc() {
        return desc;
    }
    public void setDesc(String desc) {
        this.desc = desc;
    }
    @Override
    public String toString() {
        return "Service2{" + "desc = '" + this.getDesc() + "'}";
    }
}
class Service3 implements Service {
    private String desc;
    public String getDesc() {
        return desc;
    }
    public void setDesc(String desc) {
        this.desc = desc;
    }
    @Override
    public String toString() {
        return "Service3{" + "desc = '" + this.getDesc() + "'}";
    }
}

上述目标bean定义了两个属性:serviceList和serviceMap,它们需要注入的类型都是Service。

bean xml:

<bean id="service1-1-1" class="com.zeh.main.pojo.Service1">
    <property name="desc" value="service1-1-1" />
</bean>
<bean id="service1-1-2" class="com.zeh.main.pojo.Service1">
    <property name="desc" value="service1-1-2" />
</bean>
<bean id="service2-2-1" class="com.zeh.main.pojo.Service2">
    <property name="desc" value="service2-2-1" />
</bean>
<bean id="service2-2-2" class="com.zeh.main.pojo.Service2">
    <property name="desc" value="service2-2-2" />
</bean>
<bean id="autowireBean" class="com.zeh.main.pojo.AutowireModel" autowire="byType" />

上述配置文件中,Service1类注册了两个bean,Service2注册了两个bean。因为Service1和Service2都是Service接口的实现类,因此相当于上面4个bean实例都是Service接口的实例。
此时,spring容器中Service类型的实例总共有4个:

service1-1-1、service1-1-2、service2-2-1、service2-2-2。

测试程序:

package com.zeh.main.controller;
import com.zeh.main.pojo.AutowireModel;
import com.zeh.main.util.IocUtil;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AutowireController {
    public static void main(String[] args) {
        String beanXml = "classpath:/spring/applicationContext.xml";
        ClassPathXmlApplicationContext context = IocUtil.getIocContext(beanXml);
        AutowireModel bean = context.getBean(AutowireModel.class);
        System.out.println(String.format("bean is %s", bean));
        System.out.println(String.format("serviceList is %s", bean.getServiceList()));
        System.out.println(String.format("serviceMap is %s", bean.getServiceMap()));
    }
}

测试结果:

bean is AutowireModel{serviceList = '[Service1{desc = 'service1-1-1'}, Service1{desc = 'service1-1-2'}, Service2{desc = 'service2-2-1'}, Service2{desc = 'service2-2-2'}]',serviceMap = '{service1-1-1=Service1{desc = 'service1-1-1'}, service1-1-2=Service1{desc = 'service1-1-2'}, service2-2-1=Service2{desc = 'service2-2-1'}, service2-2-2=Service2{desc = 'service2-2-2'}}'}
serviceList is [Service1{desc = 'service1-1-1'}, Service1{desc = 'service1-1-2'}, Service2{desc = 'service2-2-1'}, Service2{desc = 'service2-2-2'}]
serviceMap is {service1-1-1=Service1{desc = 'service1-1-1'}, service1-1-2=Service1{desc = 'service1-1-2'}, service2-2-1=Service2{desc = 'service2-2-1'}, service2-2-2=Service2{desc = 'service2-2-2'}}

3.4 按照构造方法进行注入(constructor)

用法:
autowire设置为constructor:

<bean id="bean名称" class="类权限定名" autowire="constructor"/>

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

AutowireModel:

package com.zeh.main.pojo;
/**
 * 功能描述
 *
 * @author zWX5331241
 * @since 2021-05-11
 */
public class AutowireModel {
    private Service1 service1;
    private Service2 service2;
    public AutowireModel() {
        System.out.println("AutowireModel()");
    }
    public AutowireModel(Service1 service1) {
        System.out.println("AutowireModel(Service1 service1)");
        this.service1 = service1;
    }
    public AutowireModel(Service1 service1, Service2 service2) {
        System.out.println("AutowireModel(Service1 service1, Service2 service2)");
        this.service1 = service1;
        this.service2 = service2;
    }
    @Override
    public String toString() {
        return "AutowireModel{" + "service1 = '" + this.service1 + "',service2 = '" + this.service2 + "'}";
    }
}
interface Service {
}
class Service1 implements Service {
    private String desc;
    public String getDesc() {
        return desc;
    }
    public void setDesc(String desc) {
        this.desc = desc;
    }
    @Override
    public String toString() {
        return "Service1{" + "desc = '" + this.getDesc() + "'}";
    }
}
class Service2 implements Service {
    private String desc;
    public String getDesc() {
        return desc;
    }
    public void setDesc(String desc) {
        this.desc = desc;
    }
    @Override
    public String toString() {
        return "Service2{" + "desc = '" + this.getDesc() + "'}";
    }
}

bean xml:

<bean id="service1" class="com.zeh.main.pojo.Service1">
    <property name="desc" value="service1" />
</bean>
<bean id="autowireBean" class="com.zeh.main.pojo.AutowireModel" autowire="constructor" />

注意上面只交给spring容器注册了一个Service1的实例。

测试程序:

package com.zeh.main.controller;
import com.zeh.main.pojo.AutowireModel;
import com.zeh.main.util.IocUtil;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AutowireController {
    public static void main(String[] args) {
        String beanXml = "classpath:/spring/applicationContext.xml";
        ClassPathXmlApplicationContext context = IocUtil.getIocContext(beanXml);
        AutowireModel bean = context.getBean(AutowireModel.class);
        System.out.println(String.format("bean is %s", bean));
    }
}

测试结果:

AutowireModel(Service1 service1)
bean is AutowireModel{service1 = 'Service1{desc = 'service1'}',service2 = 'null'}

因为上面的bean xml中只注册了一个Service1的bean,因此通过贪婪模式在遍历AutowireModel中的构造器时,跳过了2个参数的构造器,只匹配到了1个参数的构造器。
如果bean xml中再注册Service2的bean,则会匹配2个参数的构造器进行注入。

bean xml追加Service2实例的注册:

<bean id="service1" class="com.zeh.main.pojo.Service1">
    <property name="desc" value="service1" />
</bean>
<bean id="service2" class="com.zeh.main.pojo.Service2">
    <property name="desc" value="service2" />
</bean>
<bean id="autowireBean" class="com.zeh.main.pojo.AutowireModel" autowire="constructor" />

测试结果:

AutowireModel(Service1 service1, Service2 service2)
bean is AutowireModel{service1 = 'Service1{desc = 'service1'}',service2 = 'Service2{desc = 'service2'}'}

发现匹配到了2个参数的构造器进行注入,满足了贪婪模式的注入原则,最大限度的注入所有依赖的对象。

3.5 autowire=”default”

用法:
bean xml的根元素是beans,注意根元素有个default-autowire属性,这个属性可选值有:

(no|byName|byType|constructor|default)

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

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-4.2.xsd"
        default-autowire="byName">
</beans>

如果default-autowire属性设置为default或者no,则相当于没有设置全局自动注入功能。
此时bean xml中对应的bean如果要使用自动注入功能,则必须自己指定autowire属性。

AutowireModel:

package com.zeh.main.pojo;
/**
 * 功能描述
 *
 * @since 2021-05-11
 */
public class AutowireModel {
    private Service1 service1;
    private Service2 service2;
    public AutowireModel() {
        System.out.println("AutowireModel()");
    }
    public AutowireModel(Service1 service1) {
        System.out.println("AutowireModel(Service1 service1)");
        this.service1 = service1;
    }
    public Service1 getService1() {
        return service1;
    }
    public void setService1(Service1 service1) {
        this.service1 = service1;
    }
    public Service2 getService2() {
        return service2;
    }
    public void setService2(Service2 service2) {
        this.service2 = service2;
    }
    @Override
    public String toString() {
        return "AutowireModel{" + "service1 = '" + this.service1 + "',service2 = '" + this.service2 + "'}";
    }
}
interface Service {
}
class Service1 implements Service {
    private String desc;
    public String getDesc() {
        return desc;
    }
    public void setDesc(String desc) {
        this.desc = desc;
    }
    @Override
    public String toString() {
        return "Service1{" + "desc = '" + this.getDesc() + "'}";
    }
}
class Service2 implements Service {
    private String desc;
    public String getDesc() {
        return desc;
    }
    public void setDesc(String desc) {
        this.desc = desc;
    }
    @Override
    public String toString() {
        return "Service2{" + "desc = '" + this.getDesc() + "'}";
    }
}

bean xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-4.2.xsd"
        default-autowire="byName">
    <bean id="service1" class="com.zeh.main.pojo.Service1">
        <property name="desc" value="service1"/>
    </bean>
    <bean id="service2" class="com.zeh.main.pojo.Service2">
        <property name="desc" value="service2"/>
    </bean>
    <!-- 采用全局默认的autowire方式 -->
    <bean id="autowireModel1" class="com.zeh.main.pojo.AutowireModel" autowire="default"/>
    <!-- 还可以自己指定自己的autowire方式以覆盖全局的方式 -->
    <bean id="autowireModel2" class="com.zeh.main.pojo.AutowireModel" autowire="constructor"/>
    <!-- 手动注入属性的方式优先级最高,可以覆盖自己的autowire方式和全局的autowire方式 -->
    <bean id="autowireModel3" class="com.zeh.main.pojo.AutowireModel" autowire="constructor">
        <property name="service1" ref="service1"/>
        <property name="service2" ref="service2"/>
    </bean>
</beans>

测试程序:

package com.zeh.main.controller;
import com.zeh.main.pojo.AutowireModel;
import com.zeh.main.util.IocUtil;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AutowireController {
    public static void main(String[] args) {
        String beanXml = "classpath:/spring/applicationContext.xml";
        ClassPathXmlApplicationContext context = IocUtil.getIocContext(beanXml);
        System.out.println(context.getBean("autowireModel1"));
        System.out.println(context.getBean("autowireModel2"));
        System.out.println(context.getBean("autowireModel3"));
    }
}

测试结果:

AutowireModel(Service1 service1)
AutowireModel{service1 = 'Service1{desc = 'service1'}',service2 = 'Service2{desc = 'service2'}'}
AutowireModel{service1 = 'Service1{desc = 'service1'}',service2 = 'null'}
AutowireModel{service1 = 'Service1{desc = 'service1'}',service2 = 'Service2{desc = 'service2'}'}

4. 总结

  1. xml手动注入存在不足之处,可以通过自动注入的方式来解决。总共介绍3种自动注入方式:通过setXXX的名称自动注入、通过setXXX的参数类型自动注入、通过构造器自动注入。
  2. 按照setXXX的参数类型自动注入有个比较牛逼的用法,可以将参数类型匹配到的所有bean注入给一个List对象,可以将参数类型匹配到的所有bean按照“bean名称->bean对象”的映射方式注入给一个Map对象,这种用法比较重要,用途很大。
  3. spring中还有其他自动注入的方式,用起来更牛逼,后续会讲解。

文档信息

Search

    Table of Contents