主頁 > 資料庫 > Spring系列第八講 自動注入(autowire)詳解,高手在于堅持!

Spring系列第八講 自動注入(autowire)詳解,高手在于堅持!

2020-10-19 06:05:51 資料庫

Spring系列第八講

  • 手動注入的不足
  • Class.isAssignableFrom方法
    • 用法
    • 案例
  • 自動注入
  • 按照名稱進行注入(byName)
    • 用法
    • 案例
    • 優缺點
  • 按照型別進行自動注入
    • 用法
    • 案例
    • 優缺點
    • 注入型別匹配的所有bean(重點)
  • 按照建構式進行自動注入
    • 用法
    • 案例
  • autowire=default
    • 用法
    • 案例
  • 總結

手動注入的不足

上篇文章中介紹了依賴注入中的手動注入,所謂手動注入是指在xml中采用硬編碼的方式來配置注入的物件,比如通過構造器注入或者set方法注入,這些注入的方式都存在不足,比如下面代碼:

public class A{
    private B b;
    private C c;
    private D d;
    private E e;
    ....
    private N n;

    //上面每個private屬性的get和set方法
}

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

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

上面的注入存在的問題:

  • 如果需要注入的物件比較多,比如A類中有幾十個屬性,那么上面的property屬性是不是需要寫幾十個,此時組態檔代碼量暴增

  • 如果A類中新增或者洗掉了一些依賴,還需要手動去調整bean xml中的依賴配置資訊,否則會報錯

  • 總的來說就是不利于維護和擴展

為了解決上面這些問題,spring為我們提供了更強大的功能:自動注入

在介紹自動注入之前需要先介紹一些基礎知識,

Class.isAssignableFrom方法

用法

isAssignableFrom是Class類中的一個方法,看一下這個方法的定義:

public native boolean isAssignableFrom(Class<?> cls)

用法如下:

c1.isAssignableFrom(c2)

用來判斷c2和c1是否相等,或者c2是否是c1的子類,

案例

@Test
public void isAssignableFrom(){
    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
}

自動注入

自動注入是采用約定大約配置的方式來實作的,程式和spring容器之間約定好,遵守某一種都認同的規則,來實作自動注入,

xml中可以在bean元素中通過autowire屬性來設定自動注入的方式:

<bean id="" class="" autowire="byType|byName|constructor|default" />
  • byteName:按照名稱進行注入

  • byType:按型別進行注入

  • constructor:按照構造方法進行注入

  • default:默認注入方式

下面我們詳解每種注入方式的用法,

按照名稱進行注入(byName)

用法

autowire設定為byName

<bean id="" class="X類" autowire="byName"/>

spring容器會按照set屬性的名稱去容器中查找同名的bean物件,然后將查找到的物件通過set方法注入到對應的bean中,未找到對應名稱的bean物件則set方法不進行注入

需要注入的set屬性的名稱和被注入的bean的名稱必須一致,

來看看案例吧,

案例

DiByName.java

package com.javacode2018.lesson001.demo6;

/**
 * 按照名稱自動注入
 */
public class DiAutowireByName {
    public static class Service1 { //@1
        private String desc;

        public String getDesc() {
            return desc;
        }

        public void setDesc(String desc) {
            this.desc = desc;
        }

        @Override
        public String toString() {
            return "Service1{" +
                    "desc='" + desc + '\'' +
                    '}';
        }
    }

    public static class Service2 { //@1
        private String desc;

        public String getDesc() {
            return desc;
        }

        public void setDesc(String desc) {
            this.desc = desc;
        }

        @Override
        public String toString() {
            return "Service2{" +
                    "desc='" + desc + '\'' +
                    '}';
        }
    }

    private Service1 service1;//@3
    private Service2 service2;//@4

    public Service1 getService1() {
        return service1;
    }

    public void setService1(Service1 service1) {
        System.out.println("setService1->" + service1);
        this.service1 = service1;
    }

    public Service2 getService2() {
        return service2;
    }

    public void setService2(Service2 service2) {
        System.out.println("setService2->" + service2);
        this.service2 = service2;
    }

    @Override
    public String toString() {
        return "DiAutowireByName{" +
                "service1=" + service1 +
                ", service2=" + service2 +
                '}';
    }
}

這個類中有2個屬性,名稱為:

  • service1

  • service2

這兩個屬性都有對應的set方法,

下面我們在bean xml中定義2個和這2個屬性同名的bean,然后使用按照名稱進行自動注入,

diAutowireByName.xml

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

    <bean id="service1" class="com.javacode2018.lesson001.demo6.DiAutowireByName$Service1">
        <property name="desc" value="service1"/>
    </bean>
    <bean id="service2" class="com.javacode2018.lesson001.demo6.DiAutowireByName$Service2">
        <property name="desc" value="service2"/>
    </bean>
    <bean id="service2-1" class="com.javacode2018.lesson001.demo6.DiAutowireByName$Service2">
        <property name="desc" value="service2-1"/>
    </bean>

    <!-- autowire:byName 配置按照name進行自動注入 -->
    <bean id="diAutowireByName1" class="com.javacode2018.lesson001.demo6.DiAutowireByName" autowire="byName"/>

    <!-- 當配置了自動注入,還可以使用手動的方式自動注入進行覆寫,手動的優先級更高一些 -->
    <bean id="diAutowireByName2" class="com.javacode2018.lesson001.demo6.DiAutowireByName" autowire="byName">
        <property name="service2" ref="service2-1"/>
    </bean>

</beans>

上面注釋認真看一下,

@1:定義了一個名稱為service1的bean

@2:定義了一個名稱為service2的bean

@3:定義diAutowireByName需要將autowire的值置為byName,表示按名稱進行自動注入,

spring容器創建diAutowireByName對應的bean時,會遍歷DiAutowireByName類中的所有set方法,然后得到set對應的屬性名稱串列:{“service1”,“service2”},然后遍歷這屬性串列,在容器中查找和屬性同名的bean物件,然后呼叫屬性對應的set方法,將bean物件注入進去

測驗用例

package com.javacode2018.lesson001.demo6;

import com.javacode2018.lesson001.demo5.IocUtils;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

public class DiAutowireTest {

    /**
     * 按照名稱進行注入
     */
    @Test
    public void diAutowireByName() {
        String beanXml = "classpath:/com/javacode2018/lesson001/demo6/diAutowireByName.xml";
        ClassPathXmlApplicationContext context = IocUtils.context(beanXml);
        System.out.println(context.getBean("diAutowireByName"));
    }
}

效果

運行diAutowireByName輸出:

setService1->Service1{desc='service1'}
setService2->Service2{desc='service2'}
setService2->Service2{desc='service2-1'}
setService1->Service1{desc='service1'}
DiAutowireByName{service1=Service1{desc='service1'}, service2=Service2{desc='service2'}}
DiAutowireByName{service1=Service1{desc='service1'}, service2=Service2{desc='service2-1'}}

優缺點

按名稱進行注入的時候,要求名稱和set屬性的名稱必須同名,相對于硬編碼的方式注入,確實節省了不少代碼,

按照型別進行自動注入

用法

autowire設定為byType

<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

package com.javacode2018.lesson001.demo6;

/**
 * 按照型別自動注入
 */
public class DiAutowireByType {
    public static 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='" + desc + '\'' +
                    '}';
        }
    }

    public static 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='" + desc + '\'' +
                    '}';
        }
    }

    private Service1 service1;
    private Service2 service2;

    public Service1 getService1() {
        return service1;
    }

    public void setService1(Service1 service1) {
        System.out.println("setService1->" + service1); //@1
        this.service1 = service1;
    }

    public Service2 getService2() {
        return service2;
    }

    public void setService2(Service2 service2) {
        System.out.println("setService2->" + service2); //@2
        this.service2 = service2;
    }

    @Override
    public String toString() {
        return "DiByType{" +
                "service1=" + service1 +
                ", service2=" + service2 +
                '}';
    }
}

DiAutowireByType類中有2個set方法分別來注入Service1和Service2,兩個set方法中都輸出了一行文字,一會執行的時候可以通過這個輸出可以看出set方法是否被呼叫了,

diAutowireByName.xml

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

    <bean id="service1" class="com.javacode2018.lesson001.demo6.DiAutowireByName$Service1">
        <property name="desc" value="service1"/>
    </bean>
    <bean id="service2" class="com.javacode2018.lesson001.demo6.DiAutowireByName$Service2">
        <property name="desc" value="service2"/>
    </bean>
    <bean id="service2-1" class="com.javacode2018.lesson001.demo6.DiAutowireByName$Service2">
        <property name="desc" value="service2-1"/>
    </bean>

    <!-- autowire:byName 配置按照name進行自動注入 -->
    <bean id="diAutowireByName1" class="com.javacode2018.lesson001.demo6.DiAutowireByName" autowire="byName"/>

    <!-- 當配置了自動注入,還可以使用手動的方式自動注入進行覆寫,手動的優先級更高一些 -->
    <bean id="diAutowireByName2" class="com.javacode2018.lesson001.demo6.DiAutowireByName" autowire="byName">
        <property name="service2" ref="service2-1"/>
    </bean>

</beans>

上面注釋認真看一下,

@1:定義了一個名稱為service1的bean

@2:定義了一個名稱為service2的bean

@3:定義diAutowireByName需要將autowire的值置為byName,表示按名稱進行自動注入,

spring容器創建diAutowireByName對應的bean時,會遍歷DiAutowireByName類中的所有set方法,然后得到set對應的屬性名稱串列:{“service1”,“service2”},然后遍歷這屬性串列,在容器中查找和屬性同名的bean物件,然后呼叫屬性對應的set方法,將bean物件注入進去

測驗用例

DiAutowireTest類中添加一個方法

/**
 * 按照set方法引數型別進行注入
 */
@Test
public void diAutowireByType() {
    String beanXml = "classpath:/com/javacode2018/lesson001/demo6/diAutowireByType.xml";
    ClassPathXmlApplicationContext context = IocUtils.context(beanXml);
    System.out.println(context.getBean("diAutowireByType1"));
}

效果

運行diAutowireByType輸出:

setService1->Service1{desc='service1'}
setService2->Service2{desc='service2'}
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

package com.javacode2018.lesson001.demo6;

import java.util.List;
import java.util.Map;

/**
 * 滿足條件的bean注入到集合中(重點)
 */
public class DiAutowireByTypeExtend {

    //定義了一個介面
    public interface IService1 {
    }

    public static class BaseServie {
        private String desc;

        public String getDesc() {
            return desc;
        }

        public void setDesc(String desc) {
            this.desc = desc;
        }

        @Override
        public String toString() {
            return "BaseServie{" +
                    "desc='" + desc + '\'' +
                    '}';
        }
    }

    //Service1實作了IService1介面
    public static class Service1 extends BaseServie implements IService1 {

    }

    //Service1實作了IService1介面
    public static class Service2 extends BaseServie implements IService1 {
    }

    private List<IService1> serviceList;//@1
    private List<BaseServie> baseServieList;//@2
    private Map<String, IService1> service1Map;//@3
    private Map<String, BaseServie> baseServieMap;//@4

    public List<IService1> getServiceList() {
        return serviceList;
    }

    public void setServiceList(List<IService1> serviceList) {//@5
        this.serviceList = serviceList;
    }

    public List<BaseServie> getBaseServieList() {
        return baseServieList;
    }

    public void setBaseServieList(List<BaseServie> baseServieList) {//@6
        this.baseServieList = baseServieList;
    }

    public Map<String, IService1> getService1Map() {
        return service1Map;
    }

    public void setService1Map(Map<String, IService1> service1Map) {//@7
        this.service1Map = service1Map;
    }

    public Map<String, BaseServie> getBaseServieMap() {
        return baseServieMap;
    }

    public void setBaseServieMap(Map<String, BaseServie> baseServieMap) {//@8
        this.baseServieMap = baseServieMap;
    }

    @Override
    public String toString() { //9
        return "DiAutowireByTypeExtend{" +
                "serviceList=" + serviceList +
                ", baseServieList=" + baseServieList +
                ", service1Map=" + service1Map +
                ", baseServieMap=" + baseServieMap +
                '}';
    }
}

@1,@2,@3,@4:定義了4個屬性,都是泛型型別的,都有對應的set方法,

@5:引數型別是List,這個集合集合中元素的型別是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新增一個方法:

/**
 * 按照型別注入集合
 */
@Test
public void diAutowireByTypeExtend() {
    String beanXml = "classpath:/com/javacode2018/lesson001/demo6/diAutowireByTypeExtend.xml";
    ClassPathXmlApplicationContext context = IocUtils.context(beanXml);
    //從容器中獲取DiAutowireByTypeExtend
    DiAutowireByTypeExtend diAutowireByTypeExtend = context.getBean(DiAutowireByTypeExtend.class);
    //輸出diAutowireByTypeExtend中的屬性看一下
    System.out.println("serviceList:" + diAutowireByTypeExtend.getServiceList());
    System.out.println("baseServieList:" + diAutowireByTypeExtend.getBaseServieList());
    System.out.println("service1Map:" + diAutowireByTypeExtend.getService1Map());
    System.out.println("baseServieMap:" + diAutowireByTypeExtend.getBaseServieMap());
}

效果

運行diAutowireByTypeExtend輸出:

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

下面我們來介紹另外一種自動注入方式,

按照建構式進行自動注入

用法

autowire設定為constructor

<bean id="" class="X類" autowire="constructor"/>

spring會找到x類中所有的構造方法(一個類可能有多個構造方法),然后將這些構造方法進行排序(先按修飾符進行排序,public的在前面,其他的在后面,如果修飾符一樣的,會按照建構式引數數量倒敘,也就是采用貪婪的模式進行匹配,spring容器會盡量多注入一些需要的物件)得到一個建構式串列,會輪詢這個構造器串列,判斷當前構造器所有引數是否在容器中都可以找到匹配的bean物件,如果可以找到就使用這個構造器進行注入,如果不能找到,那么就會跳過這個構造器,繼續采用同樣的方式匹配下一個構造器,直到找到一個合適的為止,

來看看案例吧,

案例

DiAutowireByConstructor.java

package com.javacode2018.lesson001.demo6;

/**
 * 建構式的方式進行自動注入
 */
public class DiAutowireByConstructor {

    public static class BaseServie {
        private String desc;

        public String getDesc() {
            return desc;
        }

        public void setDesc(String desc) {
            this.desc = desc;
        }

        @Override
        public String toString() {
            return "BaseServie{" +
                    "desc='" + desc + '\'' +
                    '}';
        }
    }

    //Service1實作了IService1介面
    public static class Service1 extends BaseServie {
    }

    //Service1實作了IService1介面
    public static class Service2 extends BaseServie {
    }

    private Service1 service1;
    private Service2 service2;

    public DiAutowireByConstructor() { //@0
    }

    public DiAutowireByConstructor(Service1 service1) { //@1
        System.out.println("DiAutowireByConstructor(Service1 service1)");
        this.service1 = service1;
    }

    public DiAutowireByConstructor(Service1 service1, Service2 service2) { //@2
        System.out.println("DiAutowireByConstructor(Service1 service1, Service2 service2)");
        this.service1 = service1;
        this.service2 = service2;
    }

    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 "DiAutowireByConstructor{" +
                "service1=" + service1 +
                ", service2=" + service2 +
                '}';
    }
}

@1:1個引數的建構式

@2:2個引數的建構式

2個有參建構式第一行都列印了一段文字,一會在輸出中可以看到代碼是呼叫了那個建構式創建物件,

diAutowireByConstructor.xml

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

    <bean class="com.javacode2018.lesson001.demo6.DiAutowireByConstructor$Service1">
        <property name="desc" value="service1"/>
    </bean>

    <bean id="diAutowireByConstructor" class="com.javacode2018.lesson001.demo6.DiAutowireByConstructor"
          autowire="constructor"/>

</beans>

測驗用例

DiAutowireTest新增一個方法

/**
 * 建構式的方式進行自動注入
 */
@Test
public void diAutowireByConstructor() {
    String beanXml = "classpath:/com/javacode2018/lesson001/demo6/diAutowireByConstructor.xml";
    ClassPathXmlApplicationContext context = IocUtils.context(beanXml);
    System.out.println(context.getBean("diAutowireByConstructor"));
}

效果

運行diAutowireByConstructor輸出:

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

從輸出中可以看到呼叫的是DiAutowireByConstructor類中的第一個建構式注入了service1 bean,

建構式匹配采用貪婪匹配,多個建構式結合容器找到一個合適的建構式,最匹配的就是第一個有參建構式,而第二個有參建構式的第二個引數在spring容器中找不到匹配的bean物件,所以被跳過了,

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

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

再來運行一下diAutowireByConstructor輸出:

DiAutowireByConstructor(Service1 service1, Service2 service2)
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的配置,如下:

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

</beans>

案例

diAutowireByDefault.xml

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

    <bean id="service1" class="com.javacode2018.lesson001.demo6.DiAutowireByName$Service1">
        <property name="desc" value="service1"/>
    </bean>
    <bean id="service2" class="com.javacode2018.lesson001.demo6.DiAutowireByName$Service2">
        <property name="desc" value="service2"/>
    </bean>
    <bean id="service2-1" class="com.javacode2018.lesson001.demo6.DiAutowireByName$Service2">
        <property name="desc" value="service2-1"/>
    </bean>

    <!-- autowire:default,會采用beans中的default-autowire指定的配置 -->
    <bean id="diAutowireByDefault1" class="com.javacode2018.lesson001.demo6.DiAutowireByName" autowire="default"/> //@2

    <!-- autowire:default,會采用beans中的default-autowire指定的配置,還可以使用手動的方式自動注入進行覆寫,手動的優先級更高一些 -->
    <bean id="diAutowireByDefault2" class="com.javacode2018.lesson001.demo6.DiAutowireByName" autowire="default"> //@3
        <property name="service2" ref="service2-1"/>
    </bean>

</beans>

注意上面的@1配置的default-autowire=“byName”,表示全域默認的自動注入方式是:按名稱注入

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

測驗用例

DiAutowireTest中新增一個方法

/**
 * autowire=default
 */
@Test
public void diAutowireByDefault() {
    String beanXml = "classpath:/com/javacode2018/lesson001/demo6/diAutowireByDefault.xml";
    ClassPathXmlApplicationContext context = IocUtils.context(beanXml);
    System.out.println(context.getBean("diAutowireByDefault1"));
    System.out.println(context.getBean("diAutowireByDefault2"));
}

效果

運行diAutowireByDefault輸出

setService1->Service1{desc='service1'}
setService2->Service2{desc='service2'}
setService2->Service2{desc='service2-1'}
setService1->Service1{desc='service1'}
DiAutowireByName{service1=Service1{desc='service1'}, service2=Service2{desc='service2'}}
DiAutowireByName{service1=Service1{desc='service1'}, service2=Service2{desc='service2-1'}}

總結

xml中手動注入存在的不足之處,可以通過自動注入的方式來解決,本文介紹了3中自動注入:通過名稱自動注入、通過型別自動注入、通過構造器自動注入

按型別注入中有個比較重要的是注入匹配型別所有的bean,可以將某種型別所有的bean注入給一個List物件,可以將某種型別的所有bean按照bean名稱->bean物件的映射方式注入給一個Map物件,這種用法比較重要,用途比較大,要掌握

spring中還有其他自動注入的方式,用起來會更爽,后面的文章中我們會詳細介紹,

易兮科技 Java
18級大連海事大學在校生
網路工程 & 國際經濟與貿易 雙學位
中山市易兮軟體開發有限公司創始人
易兮科技團隊負責人
Java語言愛好者

轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/179596.html

標籤:其他

上一篇:Java自學后的前十章實時復習-cnblog

下一篇:單例模式很簡單,但99%的人寫不對。

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • GPU虛擬機創建時間深度優化

    **?桔妹導讀:**GPU虛擬機實體創建速度慢是公有云面臨的普遍問題,由于通常情況下創建虛擬機屬于低頻操作而未引起業界的重視,實際生產中還是存在對GPU實體創建時間有苛刻要求的業務場景。本文將介紹滴滴云在解決該問題時的思路、方法、并展示最終的優化成果。 從公有云服務商那里購買過虛擬主機的資深用戶,一 ......

    uj5u.com 2020-09-10 06:09:13 more
  • 可編程網卡芯片在滴滴云網路的應用實踐

    **?桔妹導讀:**隨著云規模不斷擴大以及業務層面對延遲、帶寬的要求越來越高,采用DPDK 加速網路報文處理的方式在橫向縱向擴展都出現了局限性。可編程芯片成為業界熱點。本文主要講述了可編程網卡芯片在滴滴云網路中的應用實踐,遇到的問題、帶來的收益以及開源社區貢獻。 #1. 資料中心面臨的問題 隨著滴滴 ......

    uj5u.com 2020-09-10 06:10:21 more
  • 滴滴資料通道服務演進之路

    **?桔妹導讀:**滴滴資料通道引擎承載著全公司的資料同步,為下游實時和離線場景提供了必不可少的源資料。隨著任務量的不斷增加,資料通道的整體架構也隨之發生改變。本文介紹了滴滴資料通道的發展歷程,遇到的問題以及今后的規劃。 #1. 背景 資料,對于任何一家互聯網公司來說都是非常重要的資產,公司的大資料 ......

    uj5u.com 2020-09-10 06:11:05 more
  • 滴滴AI Labs斬獲國際機器翻譯大賽中譯英方向世界第三

    **桔妹導讀:**深耕人工智能領域,致力于探索AI讓出行更美好的滴滴AI Labs再次斬獲國際大獎,這次獲獎的專案是什么呢?一起來看看詳細報道吧! 近日,由國際計算語言學協會ACL(The Association for Computational Linguistics)舉辦的世界最具影響力的機器 ......

    uj5u.com 2020-09-10 06:11:29 more
  • MPP (Massively Parallel Processing)大規模并行處理

    1、什么是mpp? MPP (Massively Parallel Processing),即大規模并行處理,在資料庫非共享集群中,每個節點都有獨立的磁盤存盤系統和記憶體系統,業務資料根據資料庫模型和應用特點劃分到各個節點上,每臺資料節點通過專用網路或者商業通用網路互相連接,彼此協同計算,作為整體提供 ......

    uj5u.com 2020-09-10 06:11:41 more
  • 滴滴資料倉庫指標體系建設實踐

    **桔妹導讀:**指標體系是什么?如何使用OSM模型和AARRR模型搭建指標體系?如何統一流程、規范化、工具化管理指標體系?本文會對建設的方法論結合滴滴資料指標體系建設實踐進行解答分析。 #1. 什么是指標體系 ##1.1 指標體系定義 指標體系是將零散單點的具有相互聯系的指標,系統化的組織起來,通 ......

    uj5u.com 2020-09-10 06:12:52 more
  • 單表千萬行資料庫 LIKE 搜索優化手記

    我們經常在資料庫中使用 LIKE 運算子來完成對資料的模糊搜索,LIKE 運算子用于在 WHERE 子句中搜索列中的指定模式。 如果需要查找客戶表中所有姓氏是“張”的資料,可以使用下面的 SQL 陳述句: SELECT * FROM Customer WHERE Name LIKE '張%' 如果需要 ......

    uj5u.com 2020-09-10 06:13:25 more
  • 滴滴Ceph分布式存盤系統優化之鎖優化

    **桔妹導讀:**Ceph是國際知名的開源分布式存盤系統,在工業界和學術界都有著重要的影響。Ceph的架構和演算法設計發表在國際系統領域頂級會議OSDI、SOSP、SC等上。Ceph社區得到Red Hat、SUSE、Intel等大公司的大力支持。Ceph是國際云計算領域應用最廣泛的開源分布式存盤系統, ......

    uj5u.com 2020-09-10 06:14:51 more
  • es~通過ElasticsearchTemplate進行聚合~嵌套聚合

    之前寫過《es~通過ElasticsearchTemplate進行聚合操作》的文章,這一次主要寫一個嵌套的聚合,例如先對sex集合,再對desc聚合,最后再對age求和,共三層嵌套。 Aggregations的部分特性類似于SQL語言中的group by,avg,sum等函式,Aggregation ......

    uj5u.com 2020-09-10 06:14:59 more
  • 爬蟲日志監控 -- Elastc Stack(ELK)部署

    傻瓜式部署,只需替換IP與用戶 導讀: 現ELK四大組件分別為:Elasticsearch(核心)、logstash(處理)、filebeat(采集)、kibana(可視化) 下載均在https://www.elastic.co/cn/downloads/下tar包,各組件版本最好一致,配合fdm會 ......

    uj5u.com 2020-09-10 06:15:05 more
最新发布
  • day02-2-商鋪查詢快取

    功能02-商鋪查詢快取 3.商鋪詳情快取查詢 3.1什么是快取? 快取就是資料交換的緩沖區(稱作Cache),是存盤資料的臨時地方,一般讀寫性能較高。 快取的作用: 降低后端負載 提高讀寫效率,降低回應時間 快取的成本: 資料一致性成本 代碼維護成本 運維成本 3.2需求說明 如下,當我們點擊商店詳 ......

    uj5u.com 2023-04-20 08:33:24 more
  • MySQL中binlog備份腳本分享

    關于MySQL的二進制日志(binlog),我們都知道二進制日志(binlog)非常重要,尤其當你需要point to point災難恢復的時侯,所以我們要對其進行備份。關于二進制日志(binlog)的備份,可以基于flush logs方式先切換binlog,然后拷貝&壓縮到到遠程服務器或本地服務器 ......

    uj5u.com 2023-04-20 08:28:06 more
  • day02-短信登錄

    功能實作02 2.功能01-短信登錄 2.1基于Session實作登錄 2.1.1思路分析 2.1.2代碼實作 2.1.2.1發送短信驗證碼 發送短信驗證碼: 發送驗證碼的介面為:http://127.0.0.1:8080/api/user/code?phone=xxxxx<手機號> 請求方式:PO ......

    uj5u.com 2023-04-20 08:27:27 more
  • 快取與資料庫雙寫一致性幾種策略分析

    本文將對幾種快取與資料庫保證資料一致性的使用方式進行分析。為保證高并發性能,以下分析場景不考慮執行的原子性及加鎖等強一致性要求的場景,僅追求最終一致性。 ......

    uj5u.com 2023-04-20 08:26:48 more
  • sql陳述句優化

    問題查找及措施 問題查找 需要找到具體的代碼,對其進行一對一優化,而非一直把關注點放在服務器和sql平臺 降低簡化每個事務中處理的問題,盡量不要讓一個事務拖太長的時間 例如檔案上傳時,應將檔案上傳這一步放在事務外面 微軟建議 4.啟動sql定時執行計劃 怎么啟動sqlserver代理服務-百度經驗 ......

    uj5u.com 2023-04-20 08:26:35 more
  • 云時代,MySQL到ClickHouse資料同步產品對比推薦

    ClickHouse 在執行分析查詢時的速度優勢很好的彌補了MySQL的不足,但是對于很多開發者和DBA來說,如何將MySQL穩定、高效、簡單的同步到 ClickHouse 卻很困難。本文對比了 NineData、MaterializeMySQL(ClickHouse自帶)、Bifrost 三款產品... ......

    uj5u.com 2023-04-20 08:26:29 more
  • sql陳述句優化

    問題查找及措施 問題查找 需要找到具體的代碼,對其進行一對一優化,而非一直把關注點放在服務器和sql平臺 降低簡化每個事務中處理的問題,盡量不要讓一個事務拖太長的時間 例如檔案上傳時,應將檔案上傳這一步放在事務外面 微軟建議 4.啟動sql定時執行計劃 怎么啟動sqlserver代理服務-百度經驗 ......

    uj5u.com 2023-04-20 08:25:13 more
  • Redis 報”OutOfDirectMemoryError“(堆外記憶體溢位)

    Redis 報錯“OutOfDirectMemoryError(堆外記憶體溢位) ”問題如下: 一、報錯資訊: 使用 Redis 的業務介面 ,產生 OutOfDirectMemoryError(堆外記憶體溢位),如圖: 格式化后的報錯資訊: { "timestamp": "2023-04-17 22: ......

    uj5u.com 2023-04-20 08:24:54 more
  • day02-2-商鋪查詢快取

    功能02-商鋪查詢快取 3.商鋪詳情快取查詢 3.1什么是快取? 快取就是資料交換的緩沖區(稱作Cache),是存盤資料的臨時地方,一般讀寫性能較高。 快取的作用: 降低后端負載 提高讀寫效率,降低回應時間 快取的成本: 資料一致性成本 代碼維護成本 運維成本 3.2需求說明 如下,當我們點擊商店詳 ......

    uj5u.com 2023-04-20 08:24:03 more
  • day02-短信登錄

    功能實作02 2.功能01-短信登錄 2.1基于Session實作登錄 2.1.1思路分析 2.1.2代碼實作 2.1.2.1發送短信驗證碼 發送短信驗證碼: 發送驗證碼的介面為:http://127.0.0.1:8080/api/user/code?phone=xxxxx<手機號> 請求方式:PO ......

    uj5u.com 2023-04-20 08:23:11 more