第二章 bean的裝配

target

掌握依賴注入的三種方式
掌握基于xml的bean裝配
掌握基于注解的bean裝配
掌握bean的自動裝配
掌握注解 @Autowired 和 @Resource

1. 依賴注入

當一個bean創(chuàng)建出來后乡翅,是一個空對象女蜈,需要給bean進行賦值哼蛆,這個bean才有意義兆龙。依賴注入就是給IoC中的bean進行賦值,一般可以分為三種。

1.1 set注入

以前的開發(fā)中,當創(chuàng)建完bean對象后,一般會使用set方法給對象進行賦值鹉梨。

set注入,顧名思義就是用實體類的setter方法進行注入穿稳。
set注入是用的是最多的注入方式存皂。
注入用的標簽是property。

??新建 Java項目Spring-02逢艘,給Teacher和Course進行注入:

第一步:在src下新建實體類:

Teacher.java:

package com.lee.spring.bean;

public class Teacher {
   private int no;//工號
   private String name;//姓名

   // getter旦袋、setter、toString略
}

Course.java

package com.lee.spring.bean;

public class Course {

   private String courseName;//課程名字
   private int courseHours;//課時量
   private Teacher courseTeacher;//授課老師

   / / getter它改、setter疤孕、toString略

}

第二步:在src下新建配置文件 applicationContext.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.xsd">

 <!-- 將老師信息注入到IOC容器 -->
 <bean id="teacher" class="com.lee.spring.bean.Teacher">
     <property name="name" value="張三"></property>
     <property name="no" value="1001"></property>
 </bean>

 <!-- 將課程信息注入到IOC容器 -->
 <bean id="course" class="com.lee.spring.bean.Course">
     <property name="courseName" value="語文"></property>
     <property name="courseHours" value="200"></property>
     <property name="courseTeacher" ref="teacher"></property>
 </bean>

</beans>

注意:
在賦值的時候,如果是簡單類型(8個基本類型 + String)央拖,用value賦值祭阀。如果是對象類型,用ref(ref是reference的簡寫鲜戒,引用的意思)专控。

第三步:編寫一個測試類進行測試:

package com.lee.spring.test;

public class TestDemo {

    @Test
    public void test01() {
      //獲取上下文對象:Context
      ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
      //獲取bean對象
      Course course = (Course)context.getBean("course");
      System.out.println(course);
    }
}

輸出:

Course [courseName=語文, courseHours=200, courseTeacher=Teacher [no=1001, name=張三]]

原理解釋:

setter注入用到了實體類的setter方法,和getter方法遏餐、構(gòu)造方法都沒關(guān)系伦腐。我們可以在setter方法里面加一行輸出語句驗證。

set注入底層用的是反射技術(shù)失都,bean標簽里的class是全類名柏蘑,所以可以用Class.forName("全類名")拿到這個類的所有信息,然后用new Instance方法創(chuàng)建一個對象粹庞,getmethod()方法拿到所有的set方法咳焚,在調(diào)用setter方法將值注入。

Class clz = Class.forName("全類名");
Object obj = clz.newInstance();//創(chuàng)建對象
Method method = clz.getMethod("set方法名字");//獲取setter方法
method.invoke(obj, value里面的值);//調(diào)用setter方法賦值

1.2 構(gòu)造器注入

對象的創(chuàng)建信粮,使用的是構(gòu)造方法黔攒。

構(gòu)造器注入用的是實體類的構(gòu)造方法趁啸。
注入用的標簽是constructor-arg

第一步:在src下新建實體類强缘,并且生成構(gòu)造方法

Teacher.java

package com.lee.spring.bean;

public class Teacher {
    private int no;//工號
    private String name;//姓名
    
    public Teacher(int no, String name) {
        this.no = no;
        this.name = name;
    }

    public Teacher() {
    }

    @Override
    public String toString() {
        return "Teacher [no=" + no + ", name=" + name + "]";
    }
    
}

Course.java

package com.lee.spring.bean;

public class Course {

    private String courseName;//課程名字
      private int courseHours;//課時量
      private Teacher courseTeacher;//授課老師
    
    public Course(String courseName, int courseHours, Teacher courseTeacher) {
        this.courseName = courseName;
        this.courseHours = courseHours;
        this.courseTeacher = courseTeacher;
    }

    public Course() {
    }

    @Override
    public String toString() {
        return "Course [courseName=" + courseName + ", courseHours=" + courseHours + ", courseTeacher=" + courseTeacher
                + "]";
    }
      
}

第二步:在 src下新建配置文件applicationContext.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.xsd">

  <!-- 將老師信息注入到IOC容器 -->
  <bean id="teacher" class="com.lee.spring.bean.Teacher">
        <constructor-arg name="name" value="李四"></constructor-arg>
        <constructor-arg name="no" value="2002"></constructor-arg>
  </bean>

  <!-- 將課程信息注入到IOC容器 -->
  <bean id="course" class="com.lee.spring.bean.Course">
        <constructor-arg name="courseName" value="數(shù)學(xué)"></constructor-arg>
        <constructor-arg name="courseHours" value="300"></constructor-arg>
        <constructor-arg name="courseTeacher" ref="teacher"></constructor-arg>
  </bean>

</beans>

第三步:編寫一個測試類督惰,進行測試

package com.lee.spring.test;

public class TestDemo {

    @Test
    public void test02() {
         //獲取上下文對象:Context
          ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
          //獲取bean對象
          Course course = (Course)context.getBean("course");
          System.out.println(course);
    }
}

輸出:Course [courseName=數(shù)學(xué), courseHours=300, courseTeacher=Teacher [no=2002, name=李四]]

補充:配置文件還可以這樣寫

  • 省略name:但是順序要和構(gòu)造方法中參數(shù)的順序一致
<!-- 將老師信息注入到IOC容器 -->
<bean id="teacher" class="com.lee.entity.Teacher">
  <constructor-arg  value="2002"></constructor-arg>
  <constructor-arg  value="李四"></constructor-arg>
</bean>

<!-- 將課程信息注入到IOC容器 -->
<bean id="course" class="com.lee.entity.Course">
  <constructor-arg  value="數(shù)學(xué)"></constructor-arg>
  <constructor-arg value="300"></constructor-arg>
  <constructor-arg  ref="teacher"></constructor-arg>
</bean>
  • 用index:下標要從0開始
<!-- 將老師信息注入到IOC容器 -->
<bean id="teacher" class="com.lee.entity.Teacher">
  <constructor-arg  index="0" value="2002"></constructor-arg>
  <constructor-arg index="1" value="李四"></constructor-arg>
</bean>

<!-- 將課程信息注入到IOC容器 -->
<bean id="course" class="com.lee.entity.Course">
  <constructor-arg  index="0" value="數(shù)學(xué)"></constructor-arg>
  <constructor-arg  index="1" value="300"></constructor-arg>
  <constructor-arg  index="2" ref="teacher"></constructor-arg>
</bean>

原理解釋:

構(gòu)造器注入用到了實體類的構(gòu)造方法。我們可以在構(gòu)造方法里面加一行輸出語句驗證旅掂。

構(gòu)造器注入底層用的也是反射技術(shù)赏胚,bean標簽里的class是全類名,所以可以用Class.forName("全類名")拿到這個類的所有信息商虐,然后用getConstructor()方法獲取構(gòu)造器觉阅,調(diào)用newInstance()方法就可以創(chuàng)造出對象。

Class clz = Class.forName("全類名");
Constructor constructor = clz.getConstructor(int.class,String.class);
Object instance = constructor.newInstance("value里面的值");

1.3 p命名空間注入

首先需要引入p命名空間秘车,在namespaces里將p勾上典勇。然后在bean標簽里面寫就行了,注意中間要加上空格叮趴。此時直接編寫配置文件是沒有提示的割笙,當在實體類中加上setter方法,就有提示了眯亦,所以p命名空間本質(zhì)上也是用的setter注入

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

    <!-- 將老師信息注入到IOC容器 -->
    <bean id="teacher" class="com.lee.entity.Teacher" p:name="王五" p:no="3003"></bean>

    <!-- 將課程信息注入到IOC容器 -->
    <bean id="course" class="com.lee.entity.Course" p:courseName="hadoop" p:courseHours="280" p:courseTeacher-ref="teacher"></bean>
</beans>

注意:

沒有-ref就是簡單注入伤溉,p:courseName="hadoop"
-ref就是對象注入,p:courseTeacher-ref="teacher"
多個屬性賦值時妻率,中間要加空格
三種注入方式乱顾,我們絕大多數(shù)用set注入。

2. bean裝配概述

bean的裝配其實做的只有兩件事:為bean賦值宫静、組合bean之間的關(guān)系走净。

在 Spring 中提供了 3 種方法進行裝配:

  • 基于xml配置裝配bean

  • 基于注解裝配bean

  • 自動裝配

在現(xiàn)實的工作中,這 3 種方式都會被用到囊嘉,并且在學(xué)習(xí)和工作之中常澄录迹混合使用,所以這里給出一些關(guān)于這 3 種優(yōu)先級的建議:

① 最優(yōu)先:自動裝配

  • 基于約定優(yōu)于配置的原則扭粱,這種方式應(yīng)該是最優(yōu)先的

  • 好處:減少程序開發(fā)者的決定權(quán)舵鳞,簡單又不失靈活。

② 其次:基于注解裝配bean

  • 在沒有辦法使用自動裝配原則的情況下應(yīng)該優(yōu)先考慮此類方法

  • 好處:避免 XML 配置的泛濫琢蛤,也更為容易蜓堕。

  • 典型場景:一個父類有多個子類,比如學(xué)生類有兩個子類博其,一個男學(xué)生類和女學(xué)生類套才,通過 IoC 容器初始化一個學(xué)生類,容器將無法知道使用哪個子類去初始化慕淡,這個時候可以使用 Java 的注解配置去指定背伴。

③ 最后:XML 方式配置

  • 在上述方法都無法使用的情況下,那么也只能選擇 XML 配置的方式。

  • 好處:簡單易懂

通俗來講傻寂,現(xiàn)在開發(fā)中息尺,優(yōu)先考慮 注解裝配 + 自動裝配。老項目的維護疾掰,可以考慮使用 xml方式 裝配搂誉。

3. 基于xml的裝配

前面所講到的裝配都是基于xml方式的裝配,因為基于xml的裝配更容易理解静檬。

3.1 簡單裝配

簡單裝配就是給一個8個基本數(shù)據(jù)類型+String的屬性賦值炭懊,比如:

<!-- 將老師信息注入到IOC容器 -->
<bean id="teacher" class="com.lee.spring.bean.Teacher">
  <property name="name" value="張三"></property>
  <property name="no" value="1001"></property>
</bean>

3.2 集合屬性裝配

對于一些集合屬性的賦值,比如list集合拂檩、set集合侮腹、map集合、數(shù)組稻励、Properties等凯旋,我們可以這樣來賦值:

第一步:新建實體類

public class CollectionInject {

  private List<String> listElement;
  private Set<String> setElement;
  private String[] strElement;
  private Map<String,String> mapElement;
  private Properties propElement;

  //getter、setter省略

  @Override
  public String toString() {
    return "listElement=" + listElement + "\nsetElement=" + setElement + "\nstrElement="
      + Arrays.toString(strElement) + "\nmapElement=" + mapElement + "\npropElement=" + propElement ;
  }

}

第二步:在 src新建配置文件 applicationContext.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"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- 將集合注入到IOC容器 -->
    <bean id="coll" class="com.lee.spring.bean.CollectionInject">
    
        <!-- list集合注入 -->
        <property name="listElement" >
            <list>
                <value>足球</value>
                <value>籃球</value>
                <value>乒乓球</value>
            </list>
        </property>
        
        <!-- set集合注入 -->
        <property name="setElement">
            <set>
                <value>語文</value>
                <value>數(shù)學(xué)</value>
                <value>英語</value>
            </set>
        </property>
        
        <!-- 數(shù)組集合注入 -->
        <property name="strElement">
            <array>
                <value>手機</value>
                <value>電腦</value>
                <value>平板</value>
            </array>
        </property>
        
        <!-- map集合注入 -->
        <property name="mapElement">
            <map>
                <entry>
                    <key>
                        <value>shoes</value>
                    </key>
                    <value>鞋子</value>
                </entry>
                <entry>
                    <key>
                        <value>cap</value>
                    </key>
                    <value>帽子</value>
                </entry>
                <entry>
                    <key>
                        <value>coat</value>
                    </key>
                    <value>外套</value>
                </entry>
            </map>
        </property>
        
        <!-- property注入 -->
        <property name="propElement">
            <props>
                <prop key="bread">面包</prop>
                <prop key="chocolate">巧克力</prop>
                <prop key="milk">牛奶</prop>
            </props>
        </property>
    </bean>

</beans>

記憶技巧:除了properties钉迷,所有的集合賦值都在value標簽里進行至非。

第三步:在測試類中測試

@Test
public void test04() {
  //獲取上下文對象:Context
  ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
  //獲取bean對象
  CollectionInject coll = (CollectionInject)context.getBean("coll");
  System.out.println(coll);
}

輸出:

listElement=[足球, 籃球, 乒乓球]
setElement=[語文, 數(shù)學(xué), 英語]
strElement=[手機, 電腦, 平板]
mapElement={shoes=鞋子, cap=帽子, coat=外套}
propElement={bread=面包, chocolate=巧克力, milk=牛奶}

注意:

  • 其中l(wèi)ist、set糠聪、array可以混合使用

  • 也可以用構(gòu)造器賦值,和set注入一樣荒椭,就是換個標簽而已

<constructor-arg name="listElement" >
  <list>
    <value>足球</value>
    <value>籃球</value>
    <value>乒乓球</value>
  </list>
</constructor-arg>

3.3 特殊值裝配

如果我們想注入一些特殊值:>、<舰蟆、&等趣惠,可以考慮<value>標簽。

value和<value>注入的區(qū)別:

<value>標簽 value屬性
參數(shù)位置 寫在首尾標簽(<value></value>)的中間身害,不加雙引號 寫在value的屬性值中味悄,必須加雙引號
參數(shù)值包含特殊符號 方式一:使用<![CDATA[]]>標記
方式二:使用xml預(yù)定義的實體引用
使用xml預(yù)定義的實體引用
參數(shù)值帶雙引號輸出 可以 不可以

其中,xml預(yù)定義實體引用:

實體引用 符號
> &gt;
< &lt;
& &amp;

注意有分號塌鸯。

① 字符串

配置文件:

<!-- 將老師信息注入到IOC容器 -->
<bean id="teacher" class="com.lee.spring.bean.Teacher">
  <property name="name" value="王五"></property>
  <property name="no" value="5005"></property>
</bean>

測試:

@Test
public void test05() {
  //獲取上下文對象:Context
  ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
  //獲取bean對象
  Teacher teacher = (Teacher)context.getBean("teacher");
  System.out.println(teacher);
}

輸出:[no=5005, name=王五]

還可以使用<value>寫:

<!-- 將老師信息注入到IOC容器 -->
<bean id="teacher" class="com.lee.spring.bean.Teacher">
  <property name="name" ><value>王五</value></property>
  <property name="no" ><value>5005</value></property>
</bean>

我們?nèi)绻胼敵觯篬no=5005, name="王五"]侍瑟,就必須用<value>標簽:

<!-- 將老師信息注入到IOC容器 -->
<bean id="teacher2" class="com.lee.spring.bean.Teacher">
  <property name="name" ><value>"王五"</value></property>
  <property name="no" ><value>5005</value></property>
</bean>

② 特殊字符

a. 使用<value>標簽

<bean id="teacher" class="com.lee.spring.bean.Teacher">
  <property name="name">
    <value><![CDATA[<&>]]></value>
  </property>
  <property name="no" value="1001"></property>
</bean>

或者

<bean id="teacher" class="com.lee.spring.bean.Teacher">
  <property name="name">
    <value>&gt;&lt;&amp;</value>
  </property>
  <property name="no" value="1001"></property>
</bean>

b. 使用value屬性

<bean id="teacher" class="com.lee.spring.bean.Teacher">
  <property name="name" value="&gt;&lt;&amp;"></property>
  <property name="no" value="1001"></property>
</bean>

開發(fā)中絕大多數(shù)使用value屬性的方式注入

③ 賦空值

a. 空字符串""

裝配空字符串有兩種方式:

<bean id="teacher" class="com.lee.spring.bean.Teacher">
  <property name="name" value=""></property>
</bean>

或者

<bean id="teacher" class="com.lee.spring.bean.Teacher">
  <property name="name" ><value></value></property>
</bean>

b. null

null表示該對象是空的,只能這樣做:用<null>標簽

<bean id="teacher" class="com.lee.spring.bean.Teacher">
  <property name="name"> <null/></property>
</bean>

注意:不能用下面方法做

<bean id="teacher" class="com.lee.spring.bean.Teacher">
  <property name="name" value="null"></property>
</bean>

這樣表示這個人的名字叫null丙猬,而不是空涨颜。

4. 基于注解的裝配

基于注解的裝配就是不使用xml配置文件,使用注解來進行裝配茧球。

??用三層結(jié)構(gòu)中的Service層來模擬一下注解裝配庭瑰。

用配置文件的方法需要這樣做:

StudentService.java

package com.lee.spring.service;

public class StudentService {
    public void addStudent() {
        System.out.println("增加學(xué)生。抢埋。弹灭。");
    }
}

applicationContext.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"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    
    <bean id="studentService" class="com.lee.spring.service.StudentService"></bean>
</beans>

此時督暂,StudentService類就已經(jīng)納入到IOC容器中了,可以通過eclipse左邊StudentService類旁邊的S來確定是不是納入成功穷吮。

4.1 用注解裝配步驟

首先需要在配置文件中打開包掃描功能:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
    
  <!--開啟包掃描-->
    <context:component-scan base-package="com.lee.spring.service"></context:component-scan>
  
</beans>

然后在StudentService類頭上加相關(guān)注解即可:

package com.lee.spring.service;

import org.springframework.stereotype.Component;

@Component("studentService")
public class StudentService {
    public void addStudent() {
        System.out.println("增加學(xué)生损痰。。酒来。");
    }
}

說明

第一點:

@Component("studentService")
就等價于<bean id="studentService" class="com.lee.spring.service.StudentService"></bean>
注解括號里面的值就是bean的id值。

第二點:

在Spring啟動的時候肪凛,會根據(jù)<context:component-scan base-package="com.lee.spring.service"></context:component-scan>
中的base-package去掃描這個包下的所有類堰汉,如果發(fā)現(xiàn)該包下有哪個類存在組件相關(guān)的注解,就將他納入到IOC容器中伟墙。

4.2 其他注解

開發(fā)中會用到下面四個注解:

@Component:可以在三層中的任何一層中使用翘鸭,還有一些功能性的bean使用。

@Controller:控制器層使用戳葵。

@Service:service層使用就乓。

@Repository:dao層使用。

下面演示一個用@Component注解給普通的bean賦值:

第一步:直接在實體類上標注 @Component("p") 注解拱烁,p是bean的名字生蚁。

第二步:用@Value("小花")注解直接在屬性上賦值,不需要getter戏自、setter方法邦投。

  • 實體類 Person.java:
@Component("p")
public class Person {

    @Value("1001")
    private int id;
    @Value("小花")
    private String name;
    
    @Override
    public String toString() {
        return "Person [id=" + id + ", name=" + name + "]";
    }
}
  • 配置文件 applicationContext.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"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
    
  <!--開啟包掃描-->
    <context:component-scan base-package="com.lee.spring.bean"></context:component-scan>
  
</beans>
  • 測試
@Test
public void test08() {
  ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
  Person p = (Person)context.getBean("p");
  System.out.println(p);
}

輸出:Person [id=1001, name=小花]

5. 自動裝配

開發(fā)中有一個原則:約定優(yōu)于配置。所以能夠按照約定自動去裝配的盡量自動裝配擅笔。

但是需要注意:自動裝配僅適用于對象類型志衣,對于簡單類型不適用

自動裝配分為兩種猛们,一種是基于xml方式的自動裝配念脯,一種是基于注解方式的自動裝配⊥涮裕基于注解方式的自動裝配是比較常用的绿店。

5.1 基于xml的自動裝配

自動裝配分為三種,分別是 通過名字裝配庐橙、通過類型裝配惯吕、使用構(gòu)造器裝配。

① byName

  • 新建實體類:

Teacher.java

public class Teacher {

  private int no;
  private String teaName;

  //getter怕午、setter省略
  @Override
  public String toString() {
    return "Teacher [no=" + no + ", teaName=" + teaName + "]";
  }
}

Course.java

public class Course {

    private String courseName;//課程名字
    private int courseHours;//課時量
    private Teacher courseTeacher;//授課老師
    
    //getter废登、setter省略
    @Override
    public String toString() {
        return "[課程名字:" + courseName + ", 課時量:" + courseHours + ", 老師信息:" + courseTeacher + "]";
    }
    
}
  • 編寫配置文件applicationContext.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"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- 將老師信息注入到IOC容器 -->
    <bean id="teacher" class="com.lee.entity.Teacher">
        <property name="teaName" value="張三"></property>
        <property name="no" value="1001"></property>
    </bean>

    <!-- 將課程信息注入到IOC容器 -->
    <bean id="course" class="com.lee.entity.Course">
        <property name="courseName" value="語文"></property>
        <property name="courseHours" value="200"></property>
        <property name="courseTeacher" ref="teacher"></property>
    </bean>

</beans>

以上的裝配是手工裝配的。

自動裝配就是我不寫<property name="courseTeacher" ref="teacher"></property>這行代碼郁惜,想辦法讓程序自動在IOC容器中去尋找teacher這個bean堡距,答案是可以的甲锡。刪掉這行代碼,然后在course的標簽中加一句 autowire="byName" 羽戒。

運行程序缤沦,發(fā)現(xiàn)老師信息是null,說明沒有程序沒有找到對應(yīng)的teacher的bean易稠。既然是按照名字自動裝配缸废,所以得保證屬性的名字和bean的名字一致

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

    <!-- 將老師信息注入到IOC容器 -->
    <bean id="courseTeacher" class="com.lee.entity.Teacher">
        <property name="teaName" value="張三"></property>
        <property name="no" value="1001"></property>
    </bean>

    <!-- 將課程信息注入到IOC容器 -->
    <bean id="course" class="com.lee.entity.Course" autowire="byName">
        <property name="courseName" value="語文"></property>
        <property name="courseHours" value="200"></property>
    </bean>

</beans>
  • 測試
@Test
public void testAutowire() {
  //獲取上下文對象:Context
  ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
  //獲取bean對象
  Course course = (Course)context.getBean("course");
  System.out.println(course);

}

按照名字裝配,必須保證屬性名和被裝配bean的id名一致驶社。

byName裝配

② byType

byType自然就是按照類型裝配企量。

在被裝配的bean中加入autowire="byType"

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

   <!-- 將老師信息注入到IOC容器 -->
   <bean  class="com.lee.entity.Teacher">
       <property name="teaName" value="張三"></property>
       <property name="no" value="1001"></property>
   </bean>

   <!-- 將課程信息注入到IOC容器 -->
   <bean id="course" class="com.lee.entity.Course" autowire="byType">
       <property name="courseName" value="語文"></property>
       <property name="courseHours" value="200"></property>
   </bean>

</beans>

如果IOC容器中有一個bean的類型恰好是該類的引用類型,則可以按照類型自動裝配亡电。

byType裝配

弊端:

如果IOC容器中有兩個類型一樣的bean届巩,則程序不知道該裝配哪一個,就會裝配失敗份乒。

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

    <!-- 將老師信息注入到IOC容器 -->
    <bean  class="com.lee.entity.Teacher">
        <property name="teaName" value="張三"></property>
        <property name="no" value="1001"></property>
    </bean>

    <!-- 將老師2信息注入到IOC容器 -->
    <bean  class="com.lee.entity.Teacher">
        <property name="teaName" value="李四"></property>
        <property name="no" value="2002"></property>
    </bean>
    
    <!-- 將課程信息注入到IOC容器 -->
    <bean id="course" class="com.lee.entity.Course" autowire="byType">
        <property name="courseName" value="語文"></property>
        <property name="courseHours" value="200"></property>
    </bean>

</beans>

會拋這樣一個異常:

org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.lee.entity.Teacher' available: expected single matching bean but found 2: com.lee.entity.Teacher#0,com.lee.entity.Teacher#1

③ constructor

根據(jù)構(gòu)造器去自動裝配恕汇。所以實體類要有構(gòu)造方法。
配置文件: autowire="constructor"

<?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.xsd">

  <bean id="teacher" class="com.lee.spring.bean.Teacher">
      <constructor-arg name="no" value="1001"></constructor-arg>
      <constructor-arg name="name" value="張曉三"></constructor-arg>
  </bean>
  
  <bean id="course" class="com.lee.spring.bean.Course" autowire="constructor">
      <constructor-arg name="courseName" value="Spring"></constructor-arg>
      <constructor-arg name="courseHours" value="100"></constructor-arg>
  </bean>
</beans>

注意:同樣IOC容器中不能有兩個teacher類型的bean或辖,否則裝配失敗瘾英,并且拋異常。

全局自動裝配

全局自動裝配使用:default-autowire

可以給每一個類進行自動裝配颂暇,也能給全局bean都設(shè)置自動裝配方咆。

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

    <!-- 將老師信息注入到IOC容器 -->
    <bean  id ="courseTeacher" class="com.lee.entity.Teacher">
        <property name="teaName" value="張三"></property>
        <property name="no" value="1001"></property>
    </bean>
    
    <!-- 將課程信息注入到IOC容器 -->
    <bean id="course" class="com.lee.entity.Course" >
        <property name="courseName" value="語文"></property>
        <property name="courseHours" value="200"></property>
    </bean>

</beans>

注意:

局部bean的自動裝配可以覆蓋全局bean自動裝配。

5.2 基于注解的自動裝配

基于注解的自動裝配有兩種蟀架,分別是 通過類型自動裝配 和 通過名字自動裝配瓣赂。

基于注解的裝配在開發(fā)中是最常用的,一般三層架構(gòu)的裝配都是使用注解自動裝配片拍。

① @Autowired

@Autowired默認根據(jù)類型進行裝配煌集。和 byType是一樣的。

用配置文件方式模擬一個開發(fā)中的三層架構(gòu):

Dao層:

package com.lee.spring.dao;

public interface StudentDao {
    void addStudent();
}
package com.lee.spring.dao.impl;

public class StudentDaoImpl implements StudentDao {

    @Override
    public void addStudent() {
        System.out.println("添加學(xué)生...");
    }
}

Service層:

package com.lee.spring.service;

public interface StudentService {
    void addStudent();
}
package com.lee.spring.service.impl;

public class StudentServiceImpl implements StudentService{
  
  StudentDao studentDao;
    public void setStudentDao(StudentDao studentDao) {
        this.studentDao = studentDao;
    }
  
    @Override
    public void addStudent() {
        studentDao.addStudent();
    }
}

Controller層:

package com.lee.spring.controller;

public class AddStudentController {

     public void setStudentService(StudentService studentService) {
            this.studentService = studentService;
          }

          StudentService studentService;

          public void addStudent() {
            studentService.addStudent();
          }
}

配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
    
        <!-- 將控制器納入到IOC容器 -->
    <bean id="addStudentController" class="com.lee.spring.controller.AddStudentController">
        <property name="studentService" ref="studentService"></property>
    </bean> 
    
    <!-- 將studentService納入到IOC容器 -->
    <bean id="studentService" class="com.lee.spring.service.impl.StudentServiceImpl">
        <property name="studentDao" ref="studentDao"></property>
    </bean>
    
    <!-- 將studentDao納入到IOC容器 -->
    <bean id="studentDao" class="com.lee.spring.dao.impl.StudentDaoImpl"></bean>

</beans>

測試:

@Test
public void test08() {
  //獲取上下文對象:Context
  ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
  //獲取bean對象
  AddStudentController addStudentController = (AddStudentController)context.getBean("addStudentController");
  addStudentController.addStudent();
}

用注解方式實現(xiàn):

Dao層:

package com.lee.spring.dao;

public interface StudentDao {
    void addStudent();
}
package com.lee.spring.dao.impl;

@Repository
public class StudentDaoImpl implements StudentDao  {
    @Override
    public void addStudent() {
        System.out.println("添加學(xué)生...");
    }
}

Service層:

package com.lee.spring.service;

public interface StudentService {
    void addStudent();
}
package com.lee.spring.service.impl;

@Service
public class StudentServiceImpl implements StudentService{
    
    @Autowired
    StudentDao studentDao;
  
    @Override
    public void addStudent() {
        studentDao.addStudent();
    }
}

Controller層:

package com.lee.spring.controller;

@Controller
public class AddStudentController {

    @Autowired
    StudentService studentService;

    public void addStudent() {
        studentService.addStudent();
    }
}

配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
    
    <context:component-scan base-package="com.lee"></context:component-scan>

</beans>

如果IOC容器沒有StudentDao這個bean捌省,StudentService層源碼是這樣:

package com.lee.spring.service.impl;

@Service
public class StudentServiceImpl implements StudentService{
    
    @Autowired
    StudentDao studentDao;
  
    @Override
    public void addStudent() {
        studentDao.addStudent();
    }
}

當容器獲取stuService組件時苫纤,程序會報錯,因為stuService依賴StudentDao纲缓,但是IOC容器還沒有StudentDao卷拘,所以報錯。怎么讓程序不依賴StudentDao:在@AutoWired注解后加:required = false

package com.lee.spring.service.impl;

@Service
public class StudentServiceImpl implements StudentService{
    
    @Autowired(required = false)
    StudentDao studentDao;
  
    @Override
    public void addStudent() {
        studentDao.addStudent();
    }
}

② @Qualifier

當一個接口有多個實現(xiàn)類時祝高,需要用@Autowired + @Qualifier組合來區(qū)分到底調(diào)用哪個類的實現(xiàn)栗弟。

@Controller("addStudentController")
public class AddStudentController {

    @Autowired
    @Qualifier("stuService")
    StudentService studentService;
    public void addStudent() {
        studentService.addStudent();
    }
}

其中@Qualifier("stuService")括號中的stuService就是我們之前定義@Service注解的名稱。

注意:@Qualifier必須和@Autowired一起使用才有效工闺。

③ @Resource

@Resource注解是通過byName注入的乍赫。

@Controller("addStudentController")
public class AddStudentController {

    @Resource(name = "stuService")
    StudentService studentService;
  
    public void addStudent() {
        studentService.addStudent();
    }
}

④ @Resource和@Autowired區(qū)別

① @Autowired為Spring提供的注解瓣蛀。@Resource并不是Spring的注解,它的包是javax.annotation.Resource

② @Autowired按照byType注入雷厂,@Resource默認按照ByName自動注入惋增。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市改鲫,隨后出現(xiàn)的幾起案子诈皿,更是在濱河造成了極大的恐慌,老刑警劉巖像棘,帶你破解...
    沈念sama閱讀 211,743評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件稽亏,死亡現(xiàn)場離奇詭異,居然都是意外死亡讲弄,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,296評論 3 385
  • 文/潘曉璐 我一進店門依痊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來避除,“玉大人,你說我怎么就攤上這事胸嘁∑堪冢” “怎么了?”我有些...
    開封第一講書人閱讀 157,285評論 0 348
  • 文/不壞的土叔 我叫張陵性宏,是天一觀的道長群井。 經(jīng)常有香客問我,道長毫胜,這世上最難降的妖魔是什么书斜? 我笑而不...
    開封第一講書人閱讀 56,485評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮酵使,結(jié)果婚禮上荐吉,老公的妹妹穿的比我還像新娘。我一直安慰自己口渔,他們只是感情好样屠,可當我...
    茶點故事閱讀 65,581評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著缺脉,像睡著了一般痪欲。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上攻礼,一...
    開封第一講書人閱讀 49,821評論 1 290
  • 那天狭郑,我揣著相機與錄音蛆橡,去河邊找鬼。 笑死辕棚,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的词渤。 我是一名探鬼主播,決...
    沈念sama閱讀 38,960評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼蛙埂!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起遮糖,我...
    開封第一講書人閱讀 37,719評論 0 266
  • 序言:老撾萬榮一對情侶失蹤绣的,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后欲账,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體屡江,經(jīng)...
    沈念sama閱讀 44,186評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,516評論 2 327
  • 正文 我和宋清朗相戀三年赛不,在試婚紗的時候發(fā)現(xiàn)自己被綠了惩嘉。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,650評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡踢故,死狀恐怖文黎,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情殿较,我是刑警寧澤耸峭,帶...
    沈念sama閱讀 34,329評論 4 330
  • 正文 年R本政府宣布,位于F島的核電站淋纲,受9級特大地震影響劳闹,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜洽瞬,卻給世界環(huán)境...
    茶點故事閱讀 39,936評論 3 313
  • 文/蒙蒙 一本涕、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧伙窃,春花似錦偏友、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,757評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至产场,卻和暖如春鹅髓,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背京景。 一陣腳步聲響...
    開封第一講書人閱讀 31,991評論 1 266
  • 我被黑心中介騙來泰國打工窿冯, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人确徙。 一個月前我還...
    沈念sama閱讀 46,370評論 2 360
  • 正文 我出身青樓醒串,卻偏偏與公主長得像执桌,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子芜赌,可洞房花燭夜當晚...
    茶點故事閱讀 43,527評論 2 349

推薦閱讀更多精彩內(nèi)容