Spring學習總結—註冊IOC容器和使用IOC容器、在xml文件中多種bean配置實驗詳解、工廠配置、以及在類中運用註解配置

一、爲什麼需要學習Spring,以及Spring框架的作用?

(一)爲什麼需要學習Spring?

  1. 目前流行的框架比較
    目前最流行和運用最廣泛的是SpringMVC框架(Spring,SpringMVC,Mybatis)整合,其他框架不做分析,企業一般也會採取該中框架進行企業開發;是學習關於java後端的"必經之路";

(二)Spring框架的作用?

  1. 耦合性低
    它會把重複率較高的代碼進行封裝,方便再引用;它的耦合性低(程序的耦合:程序之間的依賴關係,包括類之間和方法之間的依賴),也可以說它的解耦(解耦:降低程序見的依賴關係)性高;因爲,在我們實際開發中,需要做到:編譯器不依賴,運行時才依賴;Spring中解耦的思路:第一步:使用反射來創建對象,而避免使用new關鍵字;第二步:通過讀取配置文件來獲取要創建的對象全限定類名
  2. AOP 編程的支持
    通過 Spring 的 AOP 功能,方便進行面向切面的編程,許多不容易用傳統 OOP 實現的功能可以
    通過 AOP 輕鬆應付。
  3. 聲明式事務的支持
    可以將我們從單調煩悶的事務管理代碼中解脫出來,通過聲明式方式靈活的進行事務的管理,
    提高開發效率和質量。
  4. 方便程序的測試
    可以用非容器依賴的編程方式進行幾乎所有的測試工作,測試不再是昂貴的操作,而是隨手可
    做的事情。
  5. 方便集成各種優秀框架
    Spring 可以降低各種框架的使用難度,提供了對各種優秀框架(Struts、Hibernate、Hessian、Quartz
    等)的直接支持。
  6. 降低 JavaEE API 的使用難度
    Spring 對 JavaEE API(如 JDBC、JavaMail、遠程調用等)進行了薄薄的封裝層,使這些 API 的
    使用難度大爲降低。
  7. Java 源碼是經典學習範例
    Spring 的源代碼設計精妙、結構清晰、匠心獨用,處處體現着大師對 Java 設計模式靈活運用以
    及對 Java 技術的高深造詣。它的源代碼無意是 Java 技術的最佳實踐的範例。

二、Spring框架中什麼叫IOC?,什麼叫DI?

(一)IOC(思想)(Inversion(反轉) of Control):控制反轉;

(1). 控制即:資源的獲取方式;
(2). 一種爲主動式(需要什麼資源自己創建即可),一種爲被動式(資源不是自己創建,而是交給一個容器來創建和設置);
(3). 容器:管理所有的組件(有功能的類),目的就是把主動的new資源變爲被動的接受資源;
(4). 用例子說明就是(容器)婚介所,主動獲取變爲被動接受;

(二) DI:(Dependency lnjection)依賴注入:如果說IOC是思想,那DI就是實現和操作運行;

(1). 容器能知道哪個組件(類)運行的時候,需要另外一個類(組件);容器通過反射的形式,將容器中準備好的對象注入(利用反射給屬性賦值)
(2). 只要容器管理的組件,都能使用容器提供的強大功能;

三、Spring框架實現和部署HelloWord小實例

  1. 導入jar包:
    1. 導入beans,context,core,expression核心容器(也是我們的分佈圖上面黑色部分需要導入的包)綠色的爲模塊在這裏插入圖片描述
    2. 最後,還需要導入一個日誌包,spring運行的時候依賴一個日誌包,沒有就會報錯;
  2. 配置:Spring的配置文件中,集合了Spring的ioc容器管理的所有組件(會員清單)創建要給Spring Bean Configuration File(Spring的bean配置文件)
  3. 測試:
    1. ClassPathXmlApplicationContext(ioc.xml): ioc容器的配置文件在類路徑下(但是。ider的module模塊下的src文件夾只會識別class文件,所以,我們的這個應用配置xml文件,就會報錯找不到文件)
    2. FileSystemXmlApplicationContext("D:\\IderWorkspace_Spring\\src\\ioc.xml");意思爲ioc容器的配置文件在磁盤路徑下;(我開始初學用的是這個,建議使用ClassPathXmlApplicationContext(ioc.xml):

四、bean配置實驗總結:

(一)根據bean的類型從ioc容器中獲取bean的實例,通過構造器爲bean賦值,通過p命名空間爲bean賦值設置

  1. 第一步,創建一個Person實體類
package com.atguigu.bean;


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

/**
 * @author liuqi
 * @create 2020--04--24--22:18
 */
public class Person {
    //基本類型直接使用:
    //<property name="lastName" value="李四"></property>自動的進行類型轉換;
    private String lastName="小明";
    private Integer age;
    private String gender;
    private String email;

    private Car car;
    private List<Book> books;
    private Map<String,Object> map;
    private Properties properties;
    //xxxxx
    public Person() {
    }

    public Person(String lastName, Integer age, String gender) {
        this.lastName = lastName;
        this.age = age;
        this.gender = gender;
        System.out.println("三個參構造器...age");
    }
    public Person(String lastName,String email,String gender) {
        this.lastName = lastName;
        this.gender = gender;
        this.email = email;
        System.out.println("三個參構造器...email");
    }

    public Person(String lastName, Integer age, String gender, String email) {
        this.lastName = lastName;
        this.age = age;
        this.gender = gender;
        this.email = email;
        System.out.println("有參參構造器");
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public Car getCar() {
        return car;
    }

    public void setCar(Car car) {
        this.car = car;
    }

    public List<Book> getBooks() {
        return books;
    }

    public void setBooks(List<Book> books) {
        this.books = books;
    }

    public Map<String, Object> getMap() {
        return map;
    }

    public void setMap(Map<String, Object> map) {
        this.map = map;
    }

    public Properties getProperties() {
        return properties;
    }

    public void setProperties(Properties properties) {
        this.properties = properties;
    }

    @Override
    public String toString() {
        return "Person{" +
                "lastName='" + lastName + '\'' +
                ", age=" + age +
                ", gender='" + gender + '\'' +
                ", email='" + email + '\'' +
                ", car=" + car +
                ", books=" + books +
                ", map=" + map +
                ", properties=" + properties +
                '}';
    }
}

  1. 根據Person的實體類屬性再創建Car實體類
package com.atguigu.bean;

/**
 * @author liuqi
 * @create 2020--05--15--17:45
 */
public class Car {
    private String carName;
    private String  price;
    private String color;

    public String getCarName() {
        return carName;
    }

    public void setCarName(String carName) {
        this.carName = carName;
    }

    public String getPrice() {
        return price;
    }

    public void setPrice(String price) {
        this.price = price;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    @Override
    public String toString() {
        return "Car{" +
                "carName='" + carName + '\'' +
                ", price='" + price + '\'' +
                ", color='" + color + '\'' +
                '}';
    }
}

  1. 根據Person的實體類屬性再創建Book實體類
package com.atguigu.bean;

/**
 * @author liuqi
 * @create 2020--05--15--20:37
 */
public class Book {
    private String bookName;
    private String author;

    public void initBook(){
        System.out.println("這是initBook()方法,初始化方法");
    }

    public void destroyBook(){
        System.out.println("這是destroyBook()方法,銷燬方法");
    }

    public Book() {
        System.out.println("創建book的無參構造方法");
    }

    public String getBookName() {
        return bookName;
    }

    public void setBookName(String bookName) {
        this.bookName = bookName;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    @Override
    public String toString() {
        return "Book{" +
                "bookName='" + bookName + '\'' +
                ", author='" + author + '\'' +
                '}';
    }
}

  1. 創建ioc.xml來創建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:util="http://www.springframework.org/schema/util"
       xmlns:context="http://www.springframework.org/schema/context"
       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 http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
    <!--frame:框架-->
    <!--註冊一個Person對象,Spring會自動創建這個person對象
    一個Bean標籤可以註冊一個組件(對象,類)
    class,寫要組測的組件的全類名;
    id:這個對象的唯一標識;-->

<!--
     使用property標籤爲Person對象的屬性賦值;
     name :指定屬性名;
     value:爲這個屬性賦值
-->
    <!--這種配置會調用無參構造器和set方法-->
 <!--   <bean id="person1" class="com.atguigu.bean.Person">
    <property name="lastName" value="張三"></property>
    <property name="age" value="19"></property>
    <property name="gender" value="男"></property>
    <property name="email" value="[email protected]"></property>
    </bean>-->
    <!--<bean id="person02" class="com.atguigu.bean.Person">-->
        <!--<property name="lastName" value="李四"></property>-->
        <!--<property name="age" value="19"></property>-->
        <!--<property name="gender" value="男"></property>-->
        <!--<property name="email" value="[email protected]"></property>-->
    <!--</bean>-->
    <!--constructor-arg:(最常用的,最有效的,掌握)構造器元,構造器有幾個參數就要寫幾個構造器標籤,set方法也不會調用了,直接用構造方法-->
    <bean id="person03" class="com.atguigu.bean.Person">
        <!--public Person(String lastName, Integer age, String gender, String email)-->
        <constructor-arg name="lastName" value="03"></constructor-arg>
        <constructor-arg name="age" value="19"></constructor-arg>
        <constructor-arg name="gender" value="男"></constructor-arg>
        <constructor-arg name="email" value="[email protected]"></constructor-arg>
    </bean>

    <bean id="person03.2" class="com.atguigu.bean.Person">
        <!--public Person(String lastName, Integer age, String gender, String email)-->
        <!--如果不寫name,則必須按照有參構造器的參數順序寫-->
        <constructor-arg  value="03.2"></constructor-arg>
        <constructor-arg value="19"></constructor-arg>
        <constructor-arg  value="男"></constructor-arg>
        <constructor-arg  value="[email protected]"></constructor-arg>
    </bean>

    <bean id="person03.3" class="com.atguigu.bean.Person">
        <!--public Person(String lastName, Integer age, String gender, String email)-->
        <constructor-arg  value="03.3"></constructor-arg>
        <constructor-arg  value="19"></constructor-arg>
        <!--index 從0開始 爲參數指定索引-->
        <constructor-arg  value="[email protected]" index="3"></constructor-arg>
        <constructor-arg  value="男" index="2"></constructor-arg>
    </bean>

   <!-- <bean id="person03.4" class="com.atguigu.bean.Person">
   <!--如果遇到兩個構造器,有一樣數量的參數,但是,參數的數據類型不一致時,可以使用type屬性讓構造器辨別它是什麼屬性的(重載的情況下用type可以指定參數的類型)-->
     <!-- public Person(String lastName, Integer age, String gender)-->
        <!-- public Person(String lastName,String email,String gender)-->
        <constructor-arg  value="03.4"></constructor-arg>
        <constructor-arg  value="男" index = "2"></constructor-arg>
        <constructor-arg  value="19" index="1" type="java.lang.String"></constructor-arg>
    </bean>-->
     <!--爲了能夠不寫重複的標籤代碼,可以通過p名稱空間爲bean賦值,導入p名稱空間
     名稱空間:在xml中名稱空間是用來防止標籤重複的;
    1、導入名稱空間的寫法 2、直接使用-->
    <!-- <bean id="person04" class="com.atguigu.bean.Person"
           p:age="12" p:email="04.email"  p:lastName="4" p:gender="男">
     </bean>-->
</beans>

  1. 創建IOCTest通過容器來測試每一個bean配置
package com.atguigu.test;

import com.atguigu.bean.Person;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;

/**
 * @author liuqi
 * @create 2020--04--24--22:27
 */
public class IOCTest  {
   private static ApplicationContext ioc = new FileSystemXmlApplicationContext("D:\\iderAllProject\\IderWorkspace_Spring\\src\\ioc.xml");
/*中文報錯意思:初始化程序錯誤異常,原因就是我用的是文件路徑,而其他地方用的時候,由於項目名不一樣就會報錯,建議使用ClassPathXmlApplicationContext()
    java.lang.ExceptionInInitializerError
    Caused by: org.springframework.beans.factory.BeanDefinitionStoreException: IOException parsing XML document from file [D:\IderWorkspace_Spring\src\ioc.xml]; nested exception is java.io.FileNotFoundException: D:\IderWorkspace_Spring\src\ioc.xml (系統找不到指定的路徑。)
*/

    //@Test的使用 是該方法可以不用main方法調用就可以測試出運行結果,是一種測試方法
    //一般函數都需要有main方法調用才能執行,注意被測試的方法必須是public修飾的
    @Test
    public void test(){
        /*ApplicationContext :容器,配置文件,上下文*/
        //ApplicationContext:代表ioc容器(Inversion of Control,縮寫爲IoC,控制反轉)
        //ClassPathXmlApplicationContext:當前應用的xml配置文件classpath下;
        //根據spring的配置文件得到ioc容器對象;
//        ApplicationContext ioc =  (ApplicationContext)new ClassPathXmlApplicationContext("src/ioc.xml");
        //容器幫我們創建好了對象;
        Person person1 = (Person)ioc.getBean("person1");
        System.out.println(person1);
    }


    //實驗二:根據bean的類型從IOC容器中獲取bean的實例;
    @Test
    public void test2(){

        ApplicationContext ioc02 = new FileSystemXmlApplicationContext("D:\\IderWorkspace_Spring\\src\\ioc.xml");
        Person person02 = ioc02.getBean(Person.class);
        System.out.println(person02);
        //報錯:如果IOC容器中同種類型d的bean有多個,報錯如下:
        // org.springframework.beans.factory.NoUnique(唯一的)BeanDefinition(定義)Exception:
        // No qualifying bean of type [com.atguigu.bean.Person] is defined:
        // expected single(單個) matching(匹配) bean but found 2: person1,person02
    }
    //實驗二正確方法:(ioc.getBean("person02",Person.class);第一個參數爲bean的id標識符,第二個爲對象class)
    @Test
    public void test2True(){
        Person person02 = ioc.getBean("person02",Person.class);
        System.out.println(person02);
    }
    //實驗三:通過構造器爲bean的屬性賦值(index,type屬性介紹),通過p名稱空間爲bean賦值;
    @Test
    public void test3True(){
        Object obj = ioc.getBean("person03");
        System.out.println(obj);
    }
    @Test
    public void test3TwoTrue(){
        /*Object obj2 = ioc.getBean("person03.2");
        System.out.println(obj2);
        Object obj3 = ioc.getBean("person03.3");
        System.out.println(obj3);*/

        Object obj4 = ioc.getBean("person03.4");
        System.out.println(obj4);
        //沒寫type:三個參構造器...age
        //Person{lastName='03.4', age=19, gender='男', email='null'}
        //添加type:三個參構造器...email
        //Person{lastName='03.4', age=null, gender='男', email='19'}
    }
    @Test
    public void Test4(){
        Object person04 = ioc.getBean("person04");
        System.out.println(person04);
    }

}

  1. 報錯總結
/*1、中文報錯意思:初始化程序錯誤異常,原因就是我用的是文件路徑,而其他地方用的時候,由於項目名不一樣就會報錯,建議使用ClassPathXmlApplicationContext()
java.lang.ExceptionInInitializerError
Caused by: org.springframework.beans.factory.BeanDefinitionStoreException: IOException parsing XML document from file [D:\IderWorkspace_Spring\src\ioc.xml]; nested exception is java.io.FileNotFoundException: D:\IderWorkspace_Spring\src\ioc.xml (系統找不到指定的路徑。)
*/

 //2、報錯:如果IOC容器中同種類型d的bean有多個,報錯如下:
 // org.springframework.beans.factory.NoUnique(唯一的)BeanDefinition(定義)Exception:
 // No qualifying bean of type [com.atguigu.bean.Person] is defined:
 // expected single(單個) matching(匹配) bean but found 2: person1,person02

3、bean標籤的id名字與測試文件getBean("id")不一致報錯;
 報錯如下:
org.springframework.beans.factory.NoSuch(如此的)BeanDefinition(定義)Exception:
No bean named 'person044' is defined

4、當創建了有參構造器,在使用bean配置文件的時候,如果報錯,必須使用
<constructor-arg  value="03.4"></constructor-arg>;不可以使用property和命名空間
說明:你沒有寫無參構造器;
(相當於,你在實例化對象,new一個無參的對象再set,和new一個有參的對象)
報錯如下:( Instantiation of bean failed(bean的實例化失敗); nested exception is org.springframework.beans.BeanInstantiationException:
Could not instantiate bean class [com.atguigu.bean.Person]: No default constructor found(未找到默認構造函數);
nested exception(嵌套異常) is java.lang.NoSuchMethodException: com.atguigu.bean.Person.<init>()(初始化))

5、 報錯:如果IOC容器中同種類型的bean有多個,報錯如下:
org.springframework.beans.factory.NoUnique(唯一的)BeanDefinition(定義)Exception:
No qualifying bean of type [com.atguigu.bean.Person] is defined:
expected single(單個) matching(匹配) bean but found 2: person1,person02

6、來指定id名字;(特別注意:指定類名開頭字母小寫)
中文解釋:bean配置constructor-arg構造元的時候,沒有命名時候,變量和值變量不一致報錯(不能解決匹配的構造函數,簡單參數的參數,以避免類型歧義)
java.lang.ExceptionInInitializerError
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'person03.2' defined in file [D:\iderAllProject\IderWorkspace_Spring\src\ioc.xml]: Could not resolve matching constructor (hint: specify index/type/name arguments for simple parameters to avoid type ambiguities)
解決方法,一一覈對變量和變量值的對應關係(或者:index從0開始 爲參數指定索引-->)

(二)正確的爲各種屬性賦值

  1. 再次沿用上面的實體類,其次,重新創建一個ioc2.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:context="http://www.springframework.org/schema/context"

       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" >
   <!--實驗4:正確的爲各種屬性賦值
    1、測試使用null值;
    -->
    <bean id="car01" class="com.atguigu.bean.Car">
        <property name="carName" value="寶馬"></property>
        <property name="color" value="綠色"></property>
        <property name="price" value="30000"></property>
    </bean>

  <bean id="person1" class="com.atguigu.bean.Person">
      <!--1、原本初始值爲小明
      Person{lastName='小明', age=null, gender='null', email='null', car=null, books=null, map=null, properties=null}-->
      <!--value="null" 相當於lastName = "null" 是一個字符串null-->
      <!--<property name="lastName" value="null"></property>-->
      <property name="lastName">
          <!--進行復雜的賦值-->
          <null></null>

      </property>
      <!--2、引用類型賦值(引用外部的bean,引用內部的bean)-->
      <!--2.1 ref:引用   reference : 參考,引用   引用外部的bean-->
      <!--Object car01 = ioc2.getBean("car01");
      <property name="car" ref="car01"></property>-->

      <!--2.2:引用內部的bean:對象我們可以使用bean創建,相當於 car = new Car();不能被獲取到,只能內部使用-->
      <property name="car">
          <bean class="com.atguigu.bean.Car" ><!--id="ccar"-->
              <property name="carName" value="單車"></property>
          </bean>
      </property>

  </bean>

    <bean id="bookyy" class="com.atguigu.bean.Book">
        <property name="author" value="劉奇2"></property>
        <property name="bookName" value="書3"></property>
    </bean>

  <bean id="person03" class="com.atguigu.bean.Person">
      <property name="books">
          <!--books = new ArrayList<Book>();-->
       <list>
           <!--list標籤體中添加每一個元素-->
           <!--1、通過p名稱空間爲bean賦值,導入p名稱空間-->
           <bean class="com.atguigu.bean.Book" ><!--p:bookName="書1"-->
               <!--2、引用內部的bean-->
               <property name="author" value="劉奇"></property>
               <property name="bookName" value="書2"></property>
           </bean>
           <!--3、引用外部的bean-->
           <ref bean="bookyy"/>
       </list>
      </property>

      <!--Map<String,Object> map;-->
      <property name="map">
         <!-- map = new LinkedHashMap<>{};-->
          <map>
              <!--entry(條目)  代表一個鍵值對-->
              <entry key="key01" value="張三"></entry>
              <!--value-ref:引用外部的bean配置-->
              <entry key="key02" value-ref="bookyy"></entry>
              <!--引用內部的bean配置-->
              <entry key="key03">
                  <bean class="com.atguigu.bean.Car">
                      <property name="carName" value="包馬"></property>
                  </bean>
              </entry>
              <!--Map<String,Object> map;可以存所有-->
              <!--<entry key="key04">
                  <map></map>
              </entry>-->
          </map>
      </property>

  </bean>
    <!--entry:入口-->
    <!--util名稱空間創建集合類型的bean:方便其他bean引用-->
    <!--報錯原因:Error:(7, 45) java: 程序包org.graalvm.compiler.core.common.util不存在
    解決方法:點擊項目名右擊》Maven 專家》reimport:全部重新導入-->

<!--<bean id = "person04" class="com.atguigu.bean.Person">
    <property name="map" ref="mymap">
    </property>
</bean>-->
    <!--xmlns:util="http://www.springframework.org/schema/util"
    private Map<String,Object> map = new HashMap<String,Object>();
<util:map id="mymap">
    <entry key="01" value="liuqi1"></entry>
    <entry key="02" value="liuqi2"></entry>
    <entry key="03" value="liuqi3"></entry>
    <entry key="04">
        <bean class="com.atguigu.bean.Person">
            <property name="age" value="22"></property>
            <property name="lastName" value="liuqi4"></property>
        </bean>
    </entry>
    <entry key="05" value-ref="carc">

    </entry>
</util:map>-->
<bean id="carc" class="com.atguigu.bean.Car">
    <property name="carName" value="奇蹟"></property>
    <property name="price" value="100"></property>
    <property name="color" value="紅色"></property>
</bean>
    <bean id="person07" class="com.atguigu.bean.Person">
        <!--private Properties properties;-->
        <property name="properties">
      <!--      Properties properties = new Properties 所有的key和value都是String-->
            <props>
                <prop key="username">root</prop>
                <prop key="password">123456</prop>
            </props>
        </property>
    </bean>
    <!--級聯屬性賦值:級聯屬性:屬性的屬性-->
    <bean id = "person5" class="com.atguigu.bean.Person">
        <property name="car" ref="car01"></property>
        <property name="car.price" value="90003"></property>
    </bean>

<!--實驗6:通過繼承實現bean配置信息的重用-->
<!--實驗7:通過abstract屬性創建一個模板bean-->
    <!--parent:繼承於哪個bean-->
    <!--abstract="true" 這個bean配置是抽象的,不能獲取它的實例,只能被別人繼承-->
    <bean id = "person6" class="com.atguigu.bean.Person" abstract="true">
        <property name="lastName" value="liuqi"></property>
        <property name="age" value="5"></property>
        <property name="email" value="qq.com"></property>
    </bean>
<bean id="person7" class="com.atguigu.bean.Person" parent="person6">
    <property name="age" value="20"></property>
</bean>


</beans>
  1. 重新創建IOCTest2.class文件
package com.atguigu.test;


import com.atguigu.bean.Book;
import com.atguigu.bean.Car;
import com.atguigu.bean.Person;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;

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

/**
 * @author liuqi
 * @create 2020--05--15--20:46
 */
public class IOCTest2 {
    ApplicationContext ioc2 = new FileSystemXmlApplicationContext("D:\\iderAllProject\\IderWorkspace_Spring\\src\\ioc2.xml");
   /*private static ApplicationContext ioc2 = new FileSystemXmlApplicationContext("D:\\IderWorkspace_Spring\\src\\ioc2.xml");*/

    @Test
    public void Test1(){

        Person person1 = (Person) ioc2.getBean("person1");
        System.out.println(person1.getLastName() == null);
        //return  true
        System.out.println(person1.getCar());
        //Car{carName='寶馬', price='30000', color='綠色'}
        Car car = person1.getCar();
        Object car01 = ioc2.getBean("car01");
        System.out.println(car01);
        System.out.println(car == car01);
        // return true
    }
    @Test
    public  void  Test02(){
        Person person01 = (Person) ioc2.getBean("person1");
        Car car = person01.getCar();
        System.out.println(car);
        //Car{carName='單車', price='null', color='null'}
    }
    @Test
    public void  Test03(){
        Person person03 = (Person) ioc2.getBean("person03");
        List<Book> books = person03.getBooks();
        System.out.println(books);
        //沒有使用內部bean [Book{bookName='書1', author='null'}, Book{bookName='書3', author='劉奇2'}]
        //沒有用命名空間 [Book{bookName='書2', author='劉奇'}, Book{bookName='書3', author='劉奇2'}]

        //用命名空間同時使用了內部bean會報錯
        //org.springframework.beans.factory.parsing.BeanDefinitionParsingException: an definition parsing
        //Offending resource: file [D:\IderWorkspace_Spring\src\ioc2.xml]Configuration problem: Unexpected failure during be
        //Bean 'person03'; nested exception is org.springframework.beans.factory.parsing(解析).BeanDefinitionParsingException: Configuration problem: Property 'bookName' is already defined using both <property> and inline(內聯函數) syntax(語法). Only one approach(接近 方法) may be used per(線) property.
        //Offending resource: file [D:\IderWorkspace_Spring\src\ioc2.xml]

    }
    @Test
    public void Test04(){
        Object ccar = ioc2.getBean("ccar");
        System.out.println("---------"+ccar);
//        報錯原因是:在bean配置中id爲ccar沒有被定義;
        /*報錯代碼:
        org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'ccar' is defined
        說明:內部bean不能用id獲取*/
    }
@Test
    public void Test05(){
    Person bean = (Person)ioc2.getBean("person03");
    Map<String, Object> map = bean.getMap();
    System.out.println(map);


    /*{key01=張三, key02=Book{bookName='書3', author='劉奇2'},
    key03=Car{carName='包馬', price='null', color='null'}}*/
}
@Test
    public void Test06(){
    Person person04 = (Person) ioc2.getBean("person04");
    Map<String, Object> map = person04.getMap();
    System.out.println(map);
}
/*級聯屬性可以修改屬性的屬性,注意:原來的bean值也會被修改*/
    @Test
    public void Test07(){
        Person person05 = (Person) ioc2.getBean("person5");
        Object o = ioc2.getBean("person5");
        Car map = person05.getCar();
        System.out.println(map);
        System.out.println(o);
    }
}

  1. 錯誤總結
1、用命名空間同時使用了內部bean會報錯
org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Unexpected failure during bean definition parsing
Offending resource: file [D:\IderWorkspace_Spring\src\ioc2.xml]
Bean 'person03'; nested exception is org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Property 'bookName' is already defined using both <property> and inline syntax. Only one approach may be used per property.
Offending resource: file [D:\IderWorkspace_Spring\src\ioc2.xml]
2、引用內部的bean:對象我們可以使用bean創建,相當於 car = new Car();不能被獲取到,只能內部使用-
報錯,找不到id名字
3、引用util(工具)寫名稱空間創建集合類型的bean:方便其他bean引用
報錯原因:Error:(7, 45) java: 程序包org.graalvm.compiler.core.common.util不存在
解決方法:點擊項目名右擊&#45;&#45;》Maven 專家&#45;&#45;》reimport:全部重新導入
4、引用util(工具)寫名稱空間創建集合類型的bean:方便其他bean引用時候,報錯但無法找到元素 'util:map' 的聲明。
報錯原因:org.springframework.beans.factory.xml.XmlBeanDefinitionStoreException:
      Line 93 in XML document from file [D:\IderWorkspace_Spring\src\ioc2.xml] is invalid;
      nested exception is org.xml.sax.SAXParseException;
      lineNumber: 93; columnNumber: 22; cvc-complex-type.2.4.c:
      通配符的匹配很全面, 但無法找到元素 'util:map' 的聲明。*/
解決方法:在Spring配置文件中定義util(工具)寫名稱空間創建集合類型的bean—和相應的schemaLocation(兩個)相對應

(三)測試bean之間的依賴,作用域(單實例和多實例)、靜態和實例工廠

  1. 繼續使用前面的類並再添加一個包(Factory)和三個類(MyFactory RoomInstanceFactory RoomStaticFactory)

1.1 MyFactory

package com.atguigu.Factory;

import com.atguigu.bean.Book;
import org.springframework.beans.factory.FactoryBean;

public class MyFactory implements FactoryBean<Book> {
    //第一個獲取對象,並傳值
    public Book getObject() throws Exception {
        Book book = new Book();
        book.setBookName("劉奇自傳");
        book.setAuthor("劉奇");
        return book;
    }
//獲取對象的類型,並返回
    public Class<?> getObjectType() {
        return Book.class;
    }
//判斷對象是否是單實例(true),還是多實例(false)
    //單實例:每次創建的對象都是一樣的
    //多實例:每次創建的對象都是不一樣的
    public boolean isSingleton() {
        return true;
    }
}

1.2 **RoomInstanceFactory **

package com.atguigu.Factory;

import com.atguigu.bean.Room;

/**
 * @author liuqi
 * @create 2020--06--16--8:19
 */
public class RoomInstanceFactory {
    public Room RoomsFactory(String dx){
        System.out.println("這是實例化建造房間工廠方法");
        Room room = new Room();
        room.setDx(dx);
        room.setCs("2");
        room.setGd("10m");
        room.setYs("藍色");
        return room;
    }



}

1.3 **RoomStaticFactory **

package com.atguigu.Factory;

import com.atguigu.bean.Room;

/**
 * @author liuqi
 * @create 2020--06--16--8:19
 */
public class RoomStaticFactory {
    public static Room getRoom(String dx){
        System.out.println("這是靜態的建造房間工廠方法");
        Room room = new Room();
        room.setDx(dx);
        room.setCs("3");
        room.setGd("20m");
        room.setYs("紅色");
        return room;
    }
}

  1. 重新創建IOCTest3.class文件
package com.atguigu.test;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;

/**
 * @author liuqi
 * @create 2020--06--15--23:36
 */
public class IOCTest3{
    ApplicationContext  Ioc = new FileSystemXmlApplicationContext("D:\\iderAllProject\\IderWorkspace_Spring\\src\\ioc3.xml");

    public static void main(String[] args) {
        System.out.println("ss");
    }
    @Test
    public void Test1(){
        System.out.println("容器完成");
        //靜態工廠方法在bean配置中聲明會自動被調用;

        /*完成打印:這是靜態的建造房間工廠方法
                容器完成*/

    }


    @Test
    public void Test2(){
    /*    bean配置沒有必需的類型異常*/
//    org.springframework.beans.factory.BeanNotOfRequiredTypeException:
//    Bean named 'room' must be of type [com.atguigu.Factory.RoomStaticFactory],
//    but was actually of type [com.atguigu.bean.Room]

        Object bean = Ioc.getBean("room");
        System.out.println(bean);
/*類轉換異常*/
//java.lang.ClassCast(投擲)Exception(類轉換異常):
//class com.atguigu.bean.Room cannot be cast to class com.atguigu.Factory.RoomStaticFactory
//(com.atguigu.bean.Room and com.atguigu.Factory.RoomStaticFactory are in unnamed module of loader 'app')

    }
    @Test
    public void Test3(){
        Object roomInstanceRealize = Ioc.getBean("RoomInstanceRealize");
        System.out.println(roomInstanceRealize);
    }

    @Test
    public void Test4(){
        /*Object roomInstanceRealize = Ioc.getBean("MyFactory", MyFactory.class);
        System.out.println(roomInstanceRealize);*/
        //Ioc.getBean("MyFactory", MyFactory.class);中的參數類型不一致
        //org.springframework.beans.factory.BeanNotOfRequiredTypeException:
        // Bean named 'MyFactory' must be of type [com.atguigu.Factory.MyFactory],
        // but was actually of type [com.atguigu.bean.Book]

        Object roomInstanceRealize = Ioc.getBean("MyFactory");
        Object roomInstanceRealize2 = Ioc.getBean("MyFactory");
        System.out.println(roomInstanceRealize==roomInstanceRealize2);
    }
}

  1. 重新創建ioc3.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">
<!--實驗8bean之間的依賴(只是改變創建順序)
    原來是按照配置的順序創建bean
    改變bean創建的順序-->
    <bean id="car" class="com.atguigu.bean.Car" depends-on="person,book"></bean>
    <bean id="book" class="com.atguigu.bean.Book"></bean>
    <bean id="person" class="com.atguigu.bean.Person"></bean>
<!--實驗9:測試bean的作用域,分別創建單實例和多實例的bean
    bean的作用於:指定bean是否單實例:xxx;默認:單實例的
    prototype(原型):多實例的
    1、容器啓動默認不會去創建多實例bean
    2、獲取的時候創建這個bean
    3、每次都會創建一個新的對象;

    singleton(單例模式):單實例的,默認

    1、在容器啓動完成之前就已經創建好對象了,並保存在容器中;(無參構造方法就可以驗證)
    2、任何獲取d都是獲取之前創建好的對象;

    request:在web環境下,同一次請 求創建一個bean實例;
    session:在web環境下,同一次會話創建一個bean實例;-->
    <bean id="book2" class="com.atguigu.bean.Book" scope="prototype"></bean>
<!--實驗五:配置通過靜態工廠方法創建的bean、實例工廠方法創建的bean、FactoryBean
    bean的創建默認就是框架利用反射new出來的bean實例
    工廠模式:工廠幫我們創建對象,有一個專門幫我們創建對象的類,這個類就是工廠;-->
     <!--類名 名稱 = 類名Factory.get類名(屬性 屬性名)-->

    <!--
    靜態工廠:工廠本身不用創建對象,通過靜態方法調用,對象 = 工廠類.工廠方法名(屬性 屬性名);
    實例工廠:工廠本身需要創建對象,
                                  工廠類 對象 = new  工廠類();
                                  工廠對象.工廠方法名(屬性 屬性名)
                      兩者的區別就是一個類的方法是static靜態方法,一個不是-->

   <!-- class:指定靜態工廠的全類名;
    factory-method:指定工廠方法
    constructor(構造函數 構造器)-arg:可以爲方法指定參數;-->
<!--靜態工廠(不需要創建工廠本身)factory—method=“getroom”:指定哪個方法是工廠方法;-->
    <bean id="room" class="com.atguigu.Factory.RoomStaticFactory" factory-method="getRoom">
    <!--可以爲方法指定參數;-->
    <constructor-arg name="dx" value="100m"></constructor-arg>



</bean>
    <!-- 2、實例工廠-->
    <!-- factory-method:指定這個實例工廠中哪個方法是工廠方法;-->
    <bean id="RoomInstances" class="com.atguigu.Factory.RoomInstanceFactory"></bean>
    <!--factory-bean;指定當前對象創建使用哪個工廠;-->
    <!-- 1、先配置出實例工廠對象;
         2、先配置我們我們要創建的類 使用哪個工廠創建;
         1)、factory-bean:指定使用哪個工廠實例;
         2)、factory-method:使用哪個工廠方法;-->
 <bean id="RoomInstanceRealize" class="com.atguigu.bean.Room" factory-bean="RoomInstances" factory-method="RoomsFactory">

     <constructor-arg name="dx" value="200m"></constructor-arg>
 </bean>
  <!--  FactoryBean(是Spring規定的一個接口;)
    只要是這個接口的實現類,Spring都認爲是一個工廠;
        1、ioc容器啓動的時候不是創建實例
        2、FactoryBean:獲取的時候才創建對象;-->
<bean id="MyFactory" class="com.atguigu.Factory.MyFactory">
</bean>

   <!-- 實驗10:創建帶有生命週期方法的bean
        生命週期:bean的創建(初始化)到銷燬:
        ioc容器中註冊的bean;
                1)、單例的bean,容器啓動的時候就會創建好,容器關閉就會銷燬創建的bean;
                2)、多實例的bean,需要獲取的時候才能創建;
                我們可以爲bean自定義一些生命週期方法;spring在創建或者銷燬的時候就會調用指定的方法;
                自定義初始化方法和銷燬方法;-->
<bean id="book01" class="com.atguigu.bean.Book" destroy-method="destroyBook" init-method="initBook"></bean>
   <!--scope="prototype":範圍 作用域 適用範圍:多實例-->
<bean id="book02" class="com.atguigu.bean.Book" destroy-method="destroyBook" init-method="initBook" scope="prototype"></bean>
<!--實驗11:測試bean的後置處理器:BeanPostProcessor
Spring有一個接口:後置處理器:可以在bean的初始化前後調用方法;
-->
<bean id="BeanPostProcessor" class="com.atguigu.Importent.MyBeanPostProcess"></bean>
   <bean id="car01" class="com.atguigu.bean.Car"></bean>

<bean id="car01" class="com.atguigu.bean.Car">
    <property name="carName" value="${username}" ></property>
</bean>
    <bean id="car02" class="com.atguigu.bean.Car">
        <property name="carName" value="${username}"></property>
    </bean>
</beans>
  1. 錯誤總結
8、用的配置文件無效,嵌套異常,無法找到聲明;
報錯原因:org.springframework.beans.factory.xml.XmlBeanDefinitionStoreException:
      Line 26 in XML document from file
      [D:\iderAllProject\IderWorkspace_Spring\src\applicationContext03.xml] is invalid(無效的);
      nested(嵌套) exception is org.xml.sax.SAXParseException;
      lineNumber: 26; columnNumber: 57; cvc-complex-type.2.4.c: 通配符的匹配很全面, 但無法找到元素 'context:component-scan' 的聲明。
解決方法:在Spring配置文件中定義context命名空間和相應的schemaLocation(兩個)相對應
(xmlns:context="http://www.springframework.org/schema/context"
     http://www.springframework.org/schema/context
     http://www.springframework.org/schema/context/spring-context-3.0.xsd")

(四)創建帶有生命週期的bean和測試bean的後置處理器

  1. 創建一個MyBeanPostProcess.class文件並繼承bean的後置處理器:BeanPostProcessor
package com.atguigu.Importent;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

public class MyBeanPostProcess implements BeanPostProcessor {
/*
* 1)、編寫後置處理器的實現類;
* 2)、將後置處理器註冊在【配置文件中
* */
  /*
    * postProcessBeforeInitialization:
    *           初始化之前調用
    *       Object bean:將要初始化的bean
    *       String s:bean在xml中配置的id
    * */
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("["+beanName+"]"+"bean將要調用初始化方法了。。BeforeInitialization。"+"這個bean是這樣的["+bean+"]");
        //返回傳入的bean;
        return bean;
    }
/*
* postProcessAfterInitialization:
*           初始化方法之後調用
* */
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("["+beanName+"]"+"bean初始化方法之後調用完了。。AfterInitialization。"+"這個bean是這樣的["+bean+"]");
        //初始化之後返回的bean;返回的是什麼,容器中保存的就是什麼;
        return bean;
    }
}

  1. 創建一個applicationContext.xml文件來創建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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
   <!-- 實驗10:創建帶有生命週期方法的bean
        生命週期:bean的創建(初始化)到銷燬:
        ioc容器中註冊的bean;
                1)、單例的bean,容器啓動的時候就會創建好,容器關閉就會銷燬創建的bean;
                2)、多實例的bean,需要獲取的時候才能創建;
                我們可以爲bean自定義一些生命週期方法;spring在創建或者銷燬的時候就會調用指定的方法;
                自定義初始化方法和銷燬方法;-->
<bean id="book01" class="com.atguigu.bean.Book" destroy-method="destroyBook" init-method="initBook"></bean>
   <!--scope="prototype":範圍 作用域 適用範圍:多實例-->
<bean id="book02" class="com.atguigu.bean.Book" destroy-method="destroyBook" init-method="initBook" scope="prototype"></bean>
<!--實驗11:測試bean的後置處理器:BeanPostProcessor
Spring有一個接口:後置處理器:可以在bean的初始化前後調用方法;
-->
<bean id="BeanPostProcessor" class="com.atguigu.Importent.MyBeanPostProcess"></bean>
   <bean id="car01" class="com.atguigu.bean.Car"></bean>
</beans>
  1. 創建一個測試類IocTest.class文件
package com.atguigu.Importent;

import com.atguigu.bean.Car;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;

public class IocText {

//    ApplicationContext applicationContext =new FileSystemXmlApplicationContext("D:\\iderAllProject\\IderWorkspace_Spring\\src\\applicationContext.xml");
/*報錯原因爲:class文件找不到,用File方法一般都能找到*/
//    org.springframework.beans.factory.BeanDefinitionStoreException:
//    IOException parsing XML document from class path resource [D:/iderAllProject/IderWorkspace_Spring/src/applicationContext.xml];
//    nested exception is java.io.FileNotFoundException: class path resource [D:/iderAllProject/IderWorkspace_Spring/src/applicationContext.xml]
//    cannot be opened because it does not exist


//實驗10:創建帶有生命週期方法的bean

    //證明:
    /*單例Bean的生命週期
            (容器啓動)構造器----》初始化方法---》(容器關閉)銷燬方法(需要寫close方法)

    多實例Bean的生命週期
            (獲取bean)構造器----》初始化方法---》容器關閉也會調用bean的銷燬方法(需要寫close方法)*/
    @Test
    public void Experiment10 (){
        //創建ioc容器的時候,會直接調用init初始化方法:
        // (打印爲:創建book的無參構造方法
        //這是initBook()方法,初始化方法)
        ConfigurableApplicationContext configurableApplicationContext =new FileSystemXmlApplicationContext("D:\\iderAllProject\\IderWorkspace_Spring\\src\\applicationContext.xml");
        Object book01 = configurableApplicationContext.getBean("book01");
        System.out.println("關閉了");
//        configurableApplicationContext.close();
    }
    @Test
    public void Experiment10two (){
        ConfigurableApplicationContext configurableApplicationContext =new FileSystemXmlApplicationContext("D:\\iderAllProject\\IderWorkspace_Spring\\src\\applicationContext.xml");
        Object book02 = configurableApplicationContext.getBean("book02");
        System.out.println("Experiment10two ()關閉了");
//        configurableApplicationContext.close();
        /*創建book的無參構造方法
        這是initBook()方法,初始化方法
        Experiment10two ()關閉了
        這是destroyBook()方法,銷燬方法*/

    }
//實驗11:測試bean的後置處理器:BeanPostProcessor
    //證明1:什麼都不寫,直接實現ioc容器,爲:單實例會執行,多實例不會執行
    /*後置處理器的生命週期
            (容器啓動)構造器----》後置處理器(postProcessBeforeInitialization)----》初始化方法---》後置處理器(postProcessAfterInitialization)----》bean初始化完成*/

    //證明2:多實例執行,除非是用ioc容器獲取了它纔會執行
    /*後置處理器的生命週期
            (獲取bean)構造器----》後置處理器(postProcessBeforeInitialization)----》初始化方法---》後置處理器(postProcessAfterInitialization)----》bean初始化完成*/

    @Test
public  void  BeanPostProcessorTest(){

//結果爲:
    /*    創建book的無參構造方法
                [book01]bean將要調用初始化方法了。。BeforeInitialization。這個bean是這樣的[Book{bookName='null', author='null'}]
        這是initBook()方法,初始化方法
                [book01]bean初始化方法之後調用完了。。AfterInitialization。這個bean是這樣的[Book{bookName='null', author='null'}]*/
}
//實驗11:測試bean的後置處理器:BeanPostProcessor
//證明3:無論bean是否有初始化方法;後置處理器都會默認其有,還會繼續工作;
@Test
public void CarTest1(){
    ConfigurableApplicationContext configurableApplicationContext =new FileSystemXmlApplicationContext("D:\\iderAllProject\\IderWorkspace_Spring\\src\\applicationContext.xml");
/*
結果爲:
    [car01]bean將要調用初始化方法了。。BeforeInitialization。這個bean是這樣的[Car{carName='null', price='null', color='null'}]
[car01]bean初始化方法之後調用完了。。AfterInitialization。這個bean是這樣的[Car{carName='null', price='null', color='null'}]
*/


}
@Test
public void CarTest02(){
        ApplicationContext ioc = new FileSystemXmlApplicationContext("D:\\iderAllProject\\IderWorkspace_Spring\\src\\applicationContext02.xml");
    Car car = ioc.getBean("car01", Car.class);
    System.out.println(car);
    //Car{carName='null', price='null', color='null'}
}

}

(五)運用註解來直接創建bean實例

  1. 創建Service包下兩個類,分別是BookService.class和BookServiceExt.class,目的是爲了驗證同樣的繼承關係,在同樣配置註解時,如何辨別和運用;
    (1)BookService.class
package com.atguigu.Service;

import com.atguigu.Dao.BookDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class BookService {
    @Autowired
    private BookDao bookDao;
    public void save(){
        System.out.println("bookservice....正在調用Dao保存圖書");
        bookDao.saveBook();
    }
}

(2)BookServiceExt.class

package com.atguigu.Service;

import org.springframework.stereotype.Service;

@Service
public class BookServiceExt extends BookService {
    @Override
    public void save(){
        System.out.println("BookServiceExt......");
    }
}

  1. 創建一個Servlet包下BookServlet.class,主要是運用註解區分Dao、Servlet、Service層;辨識度高
package com.atguigu.Servlet;

import com.atguigu.Dao.BookDao;
import com.atguigu.Service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;


/*@Autowired:Spring會自動的爲這個屬性賦值;
一定是去容器中找到這個屬性對應的組件*/

@Controller
public class BookServlet {
    /*servlet(控制器)*/
    /*自動裝配*/
    /*@Qualifier(限定符 限定詞 修飾符):指定一個名作爲id,讓spring別使用變量名作爲id(前提是已經由@autowired註解查找屬性時有多個)
    * 特別注意:指定類名開頭字母小寫*/
    @Qualifier("bookServiceggg")

    //這裏多個BookService的本類和繼承類,但是沒有一個類名是bookServiceggg,所以,找不到,會報空指針異常;
    // 然後,又@Autowired(required=false),設置爲false之後,沒有強制去自動配置,如果找到則繼續,沒找到不會報錯,變量爲null

    @Autowired(required=false)
    private BookService bookServiceExt2;
    public void get(){
        //bookServiceExt2.save();
        System.out.println(".........使用required = false"+bookServiceExt2);
        /*結果爲:.........使用required = false   null*/
    }
    /*
    * 方法上有@Autowired的話;
    * 1、這個方法也會在bean創建的時候自動運行
    * 2、這個方法上的每一個參數都會自動注入值
    *
    * */
    /*裏面的變量和變量名一樣遵循@Autowired原理:*/
    @Autowired
    public  void BookTest(BookDao bookDao, @Qualifier("bookServiceExt") BookService bookService){
        System.out.println("當bean創建的時候自動運行"+bookDao+"---->"+bookService);
    }

}

  1. 創建一個Dao包下的BookDao.class類,目的也是:主要是運用註解區分Dao、Servlet、Service層;辨識度高
package com.atguigu.Dao;

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Repository;
/*<!--id默認就是類名首字母小寫-->*/
@Repository("bookdaohh")
@Scope(value = "prototype")
//作用域爲多實例
public class BookDao {
    /*Repository:資源庫,倉庫*/
    public void saveBook(){
        System.out.println("圖書已經保存");
    }
}

  1. **創建applicationContext03.xml文件,特別注意現在屬性字段上,方法,構造器,註解上等上面運用註解,其次再運用導包,並依賴context命名空間、最後再用 **<context:component-scan base-package="com.atguigu" ></context:component-scan> 來進行掃描基礎包來運行自動配置
<?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: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-3.0.xsd">


    <!--實驗15:通過註解分別創建Dao、Service、Controller(控制器:控制網站跳轉邏輯Servlet)
    通過bean上添加某些註解,可以快速的將bean加入到ioc容器中
    某個類上添加上任何一個註解都能快速的將這個組件加入到ioc容器的管理中;
    @Controller:控制器,我們推薦給控制器層(servlet包下的這些)的組件加這個註解
    @Service:業務邏輯;我們推薦業務邏輯層的組件添加這個註解;
    @Repository(倉庫,資源庫):給數據庫層(持久化層,Dao層)的組件添加這個註解
    @Component:給不屬於以上幾層的組件添加這個註解;

    註解可以隨便加:Spring底層不會去驗證你的組件;
    是否如你註解所說就是一個dao層或者就是一個servlet層的組件;
    我們推薦各自層加各自的註解,主要面對對象是給我們程序員看的;

    使用註解將組件快速的加入到容器中需要幾步;
    1)、給要添加的組件上標四個註解的任何一個
    2)、告訴Spring,自動掃描加了註解的組件;依賴context名稱空間
    3)、一定要導入aop包,支持加註解模式;
    context:component(組件)—scan(掃描):自動組件掃描
    base—package:指定掃描的基礎包,把基礎包以及他下面所有的包所有加了註解的類,自動的掃描進ioc容器-->
    <!--id默認就是類名首字母小寫-->

   <!-- /*使用註解加入到容器中的組件,和使用配置加入到容器中的組件行爲都是默認一樣的;
    1、組件的id,默認就是組件類名的首字母小寫
    2、組件的作用域,默認就是單例的;*/-->
    <context:component-scan base-package="com.atguigu" ></context:component-scan>
    <!--註解和bean配置相結合-->

    <!--實驗17:使用<context:exclude-filter指定掃描包時不包含的類-->
    <!--掃描的時候可以排除一些不要的組件
    type="annotation":指定排除規則;這裏是按照註解進行排除;標註了指定註解的組件不要
    expression="org.springframework.stereotype.Repository":註解的全類名
    type="assignable":指定排除某個具體的類,按照類排除
    expression="com.atguigu.Dao.BookDao":類的全類名-->
    <context:component-scan base-package="com.atguigu">
        <!--<context:exclude-filter type="assignable" expression="com.atguigu.Dao.BookDao"></context:exclude-filter>-->
    </context:component-scan>
    <!--實驗16:使用<context:include-filter指定掃描包時要包含的類-->
    <!--1 、只掃描進入哪些組件;默認都是全部掃描進來
        2、一定要禁用掉默認的過濾規則纔行;(use-default-filters="false")
    -->
 <!--   <context:component-scan base-package="com.atguigu" use-default-filters="false">
        <context:include-filter type="assignable" expression="com.atguigu.Dao.BookDao"></context:include-filter>
        <context:include-filter type="assignable" expression="com.atguigu.Service.BookService"></context:include-filter>
    </context:component-scan>-->
<!--DI(依賴注入Dependency Injection)-->
<!--實驗18:使用@Autowired註解實現根據類型實現自動裝配*-->
    <context:component-scan base-package="com.atguigu"></context:component-scan>
<!--實驗19:如果資源類型的bean不止一個,
    默認根據@Autowired註解標記的成員變量名作爲id查找bean,進行裝配*-->
   <!-- @Autowired原理:
    @Autowired
    private BookDao bookDao;
    1)、先按照類型去容器中找到對應的組件;bookService = ioc.getBean(BookService)
        1)、找到一個:找到就賦值
        2)、 沒找到:拋異常
        3)、 找到多個?裝配上?
            1)、按照變量名作爲id繼續裝配;BookService(bookService)、BookServiceExt(bookServiceExt)
            (例如:@Autowired
                    private BookService bookServiceExt;
                    按照這個變量名:bookServiceExt)

                    實驗20:如果根據成員變量名作爲id還是找不到bean,可以使用@Qualifier註解明確指定目標bean的id*
                    1、匹配上;裝配
                    2、沒有匹配?報錯
                    原因:因爲我們按照變量名作爲id繼續匹配的;
                        實驗21:在方法的形參位置使用@Qualifier註解
                    使用@Qualifier("bookServiceExt")指定一個新id
                            1、找到:裝配
                            2、找不到:報錯;
                            實驗22:@Autowired註解的required屬性指定某個屬性允許不被設置
    發現@Autowired標註的自動裝配的屬性默認是一定裝配上的;
                找到就裝配,找不到就拉倒;
@Autowired註解:特別注意不光可以用在變量上,也可以用在屬性字段上,方法,構造器,註解上等上面    -->
    <!--@Autowired註解、@Resource、@Inject:都是自動裝配的意思;
    @Autowired註解:
    優點:最強大;
    缺點:只適用於Spring框架自己的註解

     @Resource:javaee;java的標準;
     優點:擴展性更強,因爲是java的標準;
     如果切換成另外一個容器框架,@Resource還是可以使用的,@Autowired就不行了




    -->



</beans>
  1. 創建IOCTest4.class文件來測試
package com.atguigu.test;

import com.atguigu.Service.BookService;
import com.atguigu.Servlet.BookServlet;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;

/*
 *目的是:創建變量並給它一個@Autowired自動裝配,在一個方法裏面可以直接用(不用寫ioc容器和ioc.get)
 * 使用Spring的單元測試;
 *    1、導包:Spring單元測試包spring-test-4.0.0.RELEASE.jar
 *    2、@ContextConfiguration(locations ="")使用它來指定Spring的配置文件的位置
 *    3、@RunWith指定用哪種驅動進行單元測試,默認就是junit
 * @RunWith(SpringJUnit4ClassRunner.class)
 * 使用Spring的單元測試模塊來執行標了@Test註解的測試方法;
 * 以前的@Test註解只是由junit執行
 *好處:我們不用ioc.getbean()獲取組件了;直接Autowired組件,Spring爲我們自動裝配
 * */
//@RunWith(SpringJUnit4ClassRunner.class)
//@ContextConfiguration(locations = "classpath:applicationContext03.xml")
/*嚴重: Caught exception while allowing TestExecutionListener [org.springframework.test.context.support.DependencyInjectionTestExecutionListener@3e6fa38a] to prepare test instance [com.atguigu.test.IOCTest4@66a3ffec]
        java.lang.IllegalStateException: Failed to load ApplicationContext*/
public class IOCTest4 {
    ApplicationContext ioc = new FileSystemXmlApplicationContext("D:\\iderAllProject\\IderWorkspace_Spring\\src\\applicationContext03.xml");
//    ApplicationContext ioc = null;

    private BookService bookService;
    private BookServlet bookServlet;
    @Test
    public void UnitTest1(){
        System.out.println("bookService=="+bookService+","+"bookServlet=="+","+bookServlet);
    }


    /*使用註解加入到容器中的組件,和使用配置加入到容器中的組件行爲都是默認一樣的;
            1、組件的id,默認就是組件類名的首字母小寫
                            @Repository("別名")
                            @Repository("bookdaohh")
            2、組件的作用域,默認就是單例的;
                            @Scope("prototype")*/

    @Test
    public void AnnotationTest1(){
        /*註解Annotation comment Note*/
        Object bookDao = ioc.getBean("bookdaohh");
        Object bookDao2 = ioc.getBean("bookdaohh");
        System.out.println(bookDao == bookDao2);
        /*返回true是單實例*/
    }
    @Test
    public void AutowiredTest1(){
        BookServlet bookServlet = (BookServlet)ioc.getBean("bookServlet");
        bookServlet.get();
    }
    @Test
    public void AutowiredTest2(){
        /*@Autowired自動裝配註解可以放在方法上面*/

        /*打印結果爲:當bean創建的時候自動運行com.atguigu.Dao.BookDao@a3d8174---->com.atguigu.Service.BookService@1ba9117e*/
    }
}

  1. 報錯總結
1、用的配置文件無效,嵌套異常,無法找到聲明;
報錯原因:org.springframework.beans.factory.xml.XmlBeanDefinitionStoreException:
      Line 26 in XML document from file
      [D:\iderAllProject\IderWorkspace_Spring\src\applicationContext03.xml] is invalid(無效的);
      nested(嵌套) exception is org.xml.sax.SAXParseException;
      lineNumber: 26; columnNumber: 57; cvc-complex-type.2.4.c: 通配符的匹配很全面, 但無法找到元素 'context:component-scan' 的聲明。
解決方法:在Spring配置文件中定義context命名空間和相應的schemaLocation(兩個)相對應
(xmlns:context="http://www.springframework.org/schema/context"
     http://www.springframework.org/schema/context
     http://www.springframework.org/schema/context/spring-context-3.0.xsd")

2、中文解釋:創建bean配置異常,不能自動裝配private com.atguigu.Service.BookService com.atguigu.Servlet.BookServlet.bookServiceExt2;
在自動裝配的時候有兩個一樣的變量,但是配置變量名bookServiceExt2異常
org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'bookServlet':
Injection of autowired dependencies failed;
nested exception is org.springframework.beans.factory.BeanCreationException:
Could not autowire field: private com.atguigu.Service.BookService com.atguigu.Servlet.BookServlet.bookServiceExt2;
nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException:
No qualifying bean of type [com.atguigu.Service.BookService] is defined: expected single matching bean but found 2: bookService,bookServiceExt
解決辦法;面對這種情況,有兩個一樣的變量,則使用@Qualifier:指定一個名作爲id,讓spring別使用變量名作爲id(前提是已經由@autowired註解查找屬性時有多個)




這裏就把基本的bean配置和到註解實驗驗證完畢;後面開始就需要學習AOP了哦!

如有不懂可以加我並練習哦;
個人也有免費大學生畢業網站和答辯項目總集;
並提供免費軟件和教學視頻;
QQ+2545062785

此文章的一部分圖片和所用學習筆記,學習歷程來源於B站的UP主雷Java-spring-springmvc-mybatis-雷豐陽版-ssm一站式學習-尚硅谷,點擊該段話,跳轉視頻地址

把此作爲筆記,如有侵權或者不允許截圖等,會馬上刪除的,謝謝!


以上總結,當採納和對你有幫助時;
🤞👣👀👇🤝🙌🍗
留下你的點贊足跡+你愛心的評論哦!
🉐(⓿_⓿)謝啦!!☆⌒(*^-゜)v

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章