JavaWeb-10-Spring基本特性-IOC

Table of Contents

Spring框架

一:整體介紹

1:主要功能

2:框架概括

3:Spring的優良特性

4:Spring各個功能需要導入的包

二:Spring的IOC

1:IOC(Inversion of control)控制翻轉介紹

1.1:控制:資源的獲取方式;

1.2:容器定義

1.3:ioc的現實舉例說明

2:DI (Dependency Injection)依賴注入;

3:IOC的Helloworld

3.1:導包

3.2:創建bean實體類

3.3:寫bean的配置文件

3.4:測試能否獲取該實例

3.5:HelloWord總結

4:ioc利用getBean(類名.class)來得到實例

5:ioc利用bean的有參構造器賦值

6:DI(依賴注入---注入各種屬性的值)

6.1:引用類型默認都是null,基本類型都是默認,如int默認爲0

6.2:bean中屬性是另一個類

6.3:爲List集合賦值

6.4:給map賦值

7:DI(依賴注入---bean繼承)

7.1:bean信息的繼承

7.2:指定抽象的實例,只能被繼承

8:depends-on;實例的依賴關係,依賴誰就先創建誰

9:scope:作用域

10:Spring利用工廠去創建實例

10.1:靜態工廠

10.2:實例工廠

10.3:使用FactoryBean工廠來創建實例

11:bean的生命週期

12:bean的後置處理器

13:ioc的自動裝配---Autowire

14:SPEL表達式

三:用註解來表達ioc

1:掃描組件:在xml中添加掃描包的路徑

1.1:掃描

1.2:掃描排除

2:改變註解的默認屬性

2.1:改變組件id

2.1:改變默認單例

3:@Autowired --- 自動注入

3.1:Autowired的使用

3.2:Autowired的原理

3.3:給方法上注入@Autowired

3.4:@Resource和@Autowired的區別

4:使用spring的單元測試

5:泛型依賴注入:


Spring框架

一:整體介紹

1:主要功能

  • 基於 Java Beans 的配置管理,採用 IOC 的原理,特別是對依賴注射技術的使用。這些都用來減少各組件間對實施細則的相互依賴性。
  • 一個核心的,全局適用的 bean 工廠 。
  •  一個一般抽象化的層面來管理數據庫間的數據處理
  • 建立在框架內的,對 Java 數據處理 API 和單獨的 JDBC 數據源的一般性策略。因此,在數據處理支持上對 Java 企業版本環境的依賴性得以消除
  • 和一些可持續性的框架,如 Hibernate,JDO,iBATIS 和 db4o,的整合
  • web 應用中的 MVC 框架,基於核心的 Spring 功能,支持多種產生視圖的技術,包括 JSP,FreeMarker,Velocity,Tiles,iText,和 POI
  • 大量的 AOP 框架以提供諸如數據處理管理的服務。同 IOC 的功能一樣,目的是提高系統的模塊化程度
  • Spring 能有效地組織 J2EE 應用各層的對象。不管是控制層的 Action 對象,還是業務層的 Service 對象,還是持久層的 DAO 對象,都可在 Spring 的管理下有機地協調、運行。Spring 將各層的對象以松耦合的方式組織在一起,Action 對象無須關心 Service 對象的具體實現,Service 對象無須關心持久層對象的具體實現,各層對象的調用完全面向接口。當系統需要重構時,代碼的改寫量將大大減少。

2:框架概括

 框架是:高度抽取可重用代碼的一種設計;高度的通用性;

框架:抽取成一種高度可重用的;事務控制,強大的servlet,項目中的一些工具。,,,

                    框架:多個可重用模塊的集合,形成一個某個領域的整體解決方案;

Spring 框架包含許多特性,並被很好地組織在下圖所示的七個模塊中。本節將
依次介紹每個模塊。

Core 封裝包是框架的最基礎部分,提供 IoC 和依賴注入特性。這裏的基礎概念是BeanFactory ,它提供對 Factory 模式的經典實現來消除對程序性單例模式的需要,並真正地允許你從程序邏輯中分離出依賴關係和配置。 

構建於 Core 封裝包基礎上的 Context 封裝包,提供了一種框架式的對象訪問方法,有些象 JNDI 註冊器。Context 封裝包的特性得自於 Beans 封裝包,並添加了對國際化(I18N)的支持(例如資源綁定),事件傳播,資源裝載的方式和 Context 的透明創建,比如說通過Servlet 容器。

DAO 提供了 JDBC 的抽象層,它可消除冗長的 JDBC 編碼和解析數據庫廠商特有的錯誤代碼。並且,JDBC 封裝包還提供了一種比編程性更好的聲明性事務管理方法,不僅僅是實現了特定接口,而且對 所有的 POJOs ( plain old Java objects ) 都適用。

ORM 封裝包提供了常用的“對象/關係”映射 APIs 的集成層。 其中包括 JPA、JDO、Hibernate 和 iBatis 。利用 ORM 封裝包,可以混合使用所有 Spring 提供的特性進行“對象/關係”映射,如前邊提到的簡單聲明性事務管理。

Spring 的 AOP 封裝包提供了符合 AOP Alliance 規範的面向方面的編程(aspect-oriented programming)實現,讓你可以定義,例如方法攔截器(method-interceptors)和切點(pointcuts),從邏輯上講,從而減弱代碼的功能耦合,清晰的被分離開。而且,利用source-level 的元數據功能,還可以將各種行爲信息合併到你的代碼中,這有點象.Net 的attribute 的概念。

Spring 中的 Web 包提供了基礎的針對 Web 開發的集成特性,例如多方文件上傳,利用Servlet listeners 進行 IoC 容器初始化和針對 Web 的 application context。當與WebWork 或 Struts 一起使用 Spring 時,這個包使 Spring 可與其他框架結合。

Spring 中的 MVC 封裝包提供了 Web 應用的 Model-View-Controller(MVC)實現。Spring 的 MVC 框架並不是僅僅提供一種傳統的實現,它提供了一種  清晰的 分離模型,在領域模型代碼和 web form 之間。並且,還可以藉助 Spring 框架的其他特性。

3:Spring的優良特性

[1]非侵入式:基於Spring開發的應用中的對象可以不依賴於Spring的API

[2]依賴注入:DI——Dependency Injection,反轉控制(IOC)最經典的實現。

[3]面向切面編程:Aspect Oriented Programming——AOP

[4]容器:Spring是一個容器,因爲它包含並且管理應用對象的生命週期

[5]組件化:Spring實現了使用簡單的組件配置組合成一個複雜的應用。在 Spring 中可以使用XML和Java註解組合這些對象。

[6]一站式:在IOC和AOP的基礎上可以整合各種企業應用的開源框架和優秀的第三方類庫(實際上Spring 自身也提供了表述層的SpringMVC和持久層的Spring JDBC)

 

容器(可以管理所有的組件(類))框架;

          核心關注:IOC和AOP;

4:Spring各個功能需要導入的包

 

Test:Spring的單元測試模塊;

     spring-test-4.0.0.RELEASE

Core Container:核心容器(IOC);黑色代表這部分的功能由哪些jar包組成;要使用這個部分的完整功能,這些jar都需要導入

spring-beans-4.0.0.RELEASE、
spring-core-4.0.0.RELEASE、
spring-context-4.0.0.RELEASE、
spring-expression-4.0.0.RELEASE

 

AOP+Aspects(面向切面編程模塊)

spring-aop-4.0.0.RELEASE
spring-aop-4.0.0.RELEASE

數據訪問/:Spring數據庫訪問模塊

spring-jdbc-4.0.0.RELEASE、spring-orm(Object Relation Mapping)-4.0.0.RELEASE、
     spring-ox(xml)m-4.0.0.RELEASE、spring-jms-4.0.0.RELEASE、(Intergration)
     spring-tx-4.0.0.RELEASE(事務)

 Web:Spring開發web應用的模塊;

 

spring-websocket(新的技術)-4.0.0.RELEASE、
spring-web-4.0.0.RELEASE、和原生的web相關(servlet)
spring-webmvc-4.0.0.RELEASE、開發web項目的(web)
spring-webmvc-portlet-4.0.0.RELEASE(開發web應用的組件集成)

二:Spring的IOC

容器是土壤

框架是架子

1:IOC(Inversion of control)控制翻轉介紹

反轉的是創建對象的過程

1.1:控制:資源的獲取方式;

                    主動式:(要什麼資源都自己創建即可)

 BookServlet{

      BookService bs = new BookService();

      AirPlane ap = new AirPlane();//複雜對象的創建是比較龐大的工程;
}

                      被動式:資源的獲取不是我們自己創建,而是交給一個容器來創建和設置;                             

 BookServlet{

     BookService bs;

     public void test01(){

      bs.checkout();// 

     }

}

容器將主動的new資源變爲被動的接受資源;

1.2:容器定義

容器:管理所有的組件(有功能的類);假設,BookServlet受容器管理,BookService也受容器管理;容器可以自動的探查出那些組件(類)需要用到另一寫組件(類);容器幫我們創建BookService對象,並把BookService對象賦值過去;

1.3:ioc的現實舉例說明

一個人(Java 實例,調用者)需要一把斧子(Java 實例,被調用者)。
(1)原始社會里,幾乎沒有社會分工。需要斧子的人(調用者)只能自己去磨一把斧子(被調用
者)。對應的情形爲:Java 程序裏的調用者自己創建被調用者。
(2)進入工業社會,工廠出現。斧子不再由普通人完成,而在工廠裏被生產出來,此時需要斧
子的人(調用者)找到工廠,購買斧子,無須關心斧子的製造過程。對應 Java 程序的簡單工廠的
設計模式。
(3)進入“按需分配”社會,需要斧子的人不需要找到工廠,坐在家裏發出一個簡單指令:需
要斧子。斧子就自然出現在他面前。對應 Spring 的依賴注入。

第一種情況下,Java 實例的調用者創建被調用的 Java 實例,必然要求被調用的 Java 類出
現在調用者的代碼裏。無法實現二者之間的松耦合。
第二種情況下,調用者無須關心被調用者具體實現過程,只需要找到符合某種標準(接口)的
實例,即可使用。此時調用的代碼面向接口編程,可以讓調用者和被調用者解耦,這也是工廠模式
大量使用的原因。但調用者需要自己定位工廠,調用者與特定工廠耦合在一起。
第三種情況下,調用者無須自己定位工廠,程序運行到需要被調用者時,系統自動提供被調
用者實例。事實上,調用者和被調用者都處於 Spring 的管理下,二者之間的依賴關係由 Spring
提供。

2:DI (Dependency Injection)依賴注入;

 

 容器能知道哪個組件(類)運行的時候,需要另外一個類(組件);容器通過反射的形式,將容器中準備好的BookService對象(依賴對象)注入(利用反射給屬性賦值)到BookServlet中;

總結來說DI依賴注入就是我們在A類中需要調用B類,那就在調用A之前,提前給我們創建好B

3:IOC的Helloworld

3.1:導包

    <dependencies>
        <!--  只導入一個就夠了,剩下的maven會自己導入  -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.6.RELEASE</version>
        </dependency>


        <!-- https://mvnrepository.com/artifact/junit/junit -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

3.2:創建bean實體類

public class Person {
    private String lastName;
    private int age;

    public String getLastName() {
        return lastName;
    }

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

    public int getAge() {
        return age;
    }

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

3.3:寫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">

    <!-- 註冊一個Person對象,Spring會自動創建這個Person對象 -->
    <!--
    一個Bean標籤可以註冊一個組件(對象、類)
    class:寫要註冊的組件的全類名
    id:這個對象的唯一標示;
    -->
    <bean id="person01" class="com.wkl.bean.Person">
        <!--使用property標籤爲Person對象的屬性賦值
            name="lastName":指定屬性名
        -->
        <property name="lastName" value="張三"></property>
        <property name="age" value="18"></property>
    </bean>

</beans>

3.4:測試能否獲取該實例

import com.wkl.bean.Person;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * Description:
 * Date:       2020/6/20 - 下午 9:35
 * author:     wangkanglu
 * version:    V1.0
 */
public class TestMain {

    @Test
    public void getBean(){
        //ApplicationContext:代表ioc容器
        //ClassPathXmlApplicationContext:當前應用的xml配置文件在 ClassPath下
        //根據spring的配置文件得到ioc容器對象,這個xml文件的位置是從類路徑下開始算的
        ApplicationContext ioc = new ClassPathXmlApplicationContext("beanXml/ioc.xml");
        //容器幫我們創建好對象了;
        Person person01 = (Person) ioc.getBean("person01");
        System.out.println("person:"+person01);
    }
}

3.5:HelloWord總結

 

new ClassPathXMlApplicationContext("ioc.xml");ioc容器的配置文件在類路徑下;

FileSystemXmlApplicationContext("F://ioc.xml");ioc容器的配置文件在磁盤路徑下;

幾個細節:
1)、ApplicationContext(IOC容器的接口),new 它相當於啓動容器
2)、給容器中註冊一個組件;我們也從容器中按照id拿到了這個組件的對象?
     組件的創建工作,是容器完成事創建的;
     Person對象是什麼時候創建好了呢?容器中對象的創建在容器創建完成的時候就已經創建好了;
3)、同一個組件在ioc容器中是單實例的;容器啓動完成都已經創建準備好的;
4)、容器中如果沒有這個組件,獲取組件?報異常
org.springframework.beans.factory.NoSuchBeanDefinitionException:No bean named 'person03' is defined
5)、ioc容器在創建這個組件對象的時候,(property)會利用setter方法爲javaBean的屬性進行賦值;
6)、javaBean的屬性名是由什麼決定的?getter/setter方法是屬性名;set去掉後面那一串首字母小寫就是屬性名;
          private String lastName;?
          所有getter/setter都自動生成!
 

4:ioc利用getBean(類名.class)來得到實例

//當該類有多個實例的時候就會報錯
Person bean = ioc.getBean(Person.class);

//同時指定bean實例的id和類名,這樣當多個實例時,不會報錯
Person person011 = ioc.getBean("person01", Person.class);

5:ioc利用bean的有參構造器賦值

    <bean id="person02" class="com.wkl.bean.Person">
        <!--   構造器中有幾個參數,就寫幾個constructor標籤     -->
        <!--如果vonstructor標籤中有name,就不用管順序,如果不寫name,順序必須和構造器一樣-->
        <constructor-arg name="lastName" value="李四"></constructor-arg>
        <constructor-arg name="age" value="19"></constructor-arg>
    </bean>

6:DI(依賴注入---注入各種屬性的值)

6.1:引用類型默認都是null,基本類型都是默認,如int默認爲0

6.2:bean中屬性是另一個類

1:利用ref進行引用

<bean id="car01" class="com.wkl.bean.Car">
        <property name="name" value="寶馬"></property>
        <property name="color" value="紅色"></property>
    </bean>
    <bean id="person01" class="com.wkl.bean.Person">
        <!--使用property標籤爲Person對象的屬性賦值
            name="lastName":指定屬性名
        -->
        <property name="lastName" value="張三"></property>
        <property name="age" value="18"></property>
        <!--  利用ref引用car01,那麼person中得到的car01和直接getBean("car01")得到的是一樣的 -->
        <property name="car" ref="car01"></property>
    </bean>

2:在屬性中在創建一個Car的bean

    <bean id="person01" class="com.wkl.bean.Person">
        <!--使用property標籤爲Person對象的屬性賦值
            name="lastName":指定屬性名
        -->
        <property name="lastName" value="張三"></property>
        <property name="age" value="18"></property>
        <!--  利用ref引用car01,那麼person中得到的car01和直接getBean("car01")得到的是一樣的 -->
        <property name="car">
            <!--   對象用bean創建,相當於這個屬性=new Car() -->
            <bean class="com.wkl.bean.Car">
                <property name="name" value="小黃車"></property>
                <property name="color" value="黃色"></property>
            </bean>
        </property>
    </bean>

6.3:爲List集合賦值

    <bean id="person01" class="com.wkl.bean.Person">
        <!--使用property標籤爲Person對象的屬性賦值
            name="lastName":指定屬性名
        -->
        <property name="lastName" value="張三"></property>
        <property name="age" value="18"></property>
        <!--  利用ref引用car01,那麼person中得到的car01和直接getBean("car01")得到的是一樣的 -->
        <property name="cars">
            <!-- 這個相當於 list = new ArrauList() -->
            <list>
                <!--       引用外部的一個bean         -->
                <ref bean="car01"/>
                <bean class="com.wkl.bean.Car">
                    <property name="name" value="第二個車"></property>
                </bean>
                <!--  當集合中類型是String是,這樣用 -->
                <value>111</value>
            </list>
        </property>
    </bean>

6.4:給map賦值

    <bean id="person01" class="com.wkl.bean.Person">
        <!--使用property標籤爲Person對象的屬性賦值
            name="lastName":指定屬性名
        -->
        <property name="lastName" value="張三"></property>
        <property name="age" value="18"></property>
        <!--給map賦值-->
        <property name="maps">
            <!--相當於創建了一個new Map()-->
            <map>
                <!--相當於創建了一個鍵值對-->
                <entry key="key01" value="111"></entry>
                <entry key="key02" value-ref="car01"></entry>
                <entry key="key03">
                    <bean class="com.wkl.bean.Car">
                        <property name="name" value="五菱"></property>
                    </bean>
                </entry>
            </map>
        </property>
    </bean>

7:DI(依賴注入---bean繼承)

7.1:bean信息的繼承

    <bean id="person01" class="com.wkl.bean.Person">
        <!--使用property標籤爲Person對象的屬性賦值
            name="lastName":指定屬性名
        -->
        <property name="lastName" value="張三"></property>
        <property name="age" value="18"></property>
    </bean>
    
    <!--parent僅代表配置信息的集成,下邊要是改就改了,不改就還是繼承來的信息-->
    <bean id="person02" parent="person01">
        <property name="lastName" value="李四"></property>
    </bean>

7.2:指定抽象的實例,只能被繼承

    <!--定義爲abstrat後,該實例只能被繼承,不能獲取這個實例-->
    <bean id="person01" class="com.wkl.bean.Person" abstract="true">
        <!--使用property標籤爲Person對象的屬性賦值
            name="lastName":指定屬性名
        -->
        <property name="lastName" value="張三"></property>
        <property name="age" value="18"></property>
    </bean>

8:depends-on;實例的依賴關係,依賴誰就先創建誰

    <!--本來是按照順序,先person01,再car01的;但是現在person01依賴car01,那就先創建car01-->
    <bean id="person01" class="com.wkl.bean.Person" depends-on="car01"></bean>
    <bean id="car01" class="com.wkl.bean.Car"></bean>

9:scope:作用域

singleton:單例模式,默認的

  • 在容器啓動前就創建好對象了,保存在容器中;
  • 任何時候獲取都是那個創建好的對象
  • (容器啓動)構造器-----初始化方法----(容器關閉)銷燬方法

prototype:多實例模式

  • 容器啓動不會去創建對象
  • 每次getBean時纔會去創建一個對象
  • (容器啓動)構造器-----初始化方法----容器關閉不會啓動bean的銷燬方法

10:Spring利用工廠去創建實例

之前的bean都是通過calss反射來創建實例的,但是現在我們可以通過工廠來創建;

工廠模式:工廠幫我們創建對象,

10.1:靜態工廠

工廠本身不用創建對象,直接工廠類.方法名;

public class PersonStaticFactory {
    //創建靜態工廠類
    public static Person getPerson(String lastname){
        Person person = new Person();
        person.setLastName(lastname);
        person.setAge(18);
        return person;
    }
}

 

    <!--calss是工廠類的全類名,factory-method指定的是靜態工廠類的方法-->
    <bean id="person01" class="com.wkl.factory.PersonStaticFactory" factory-method="getPerson">
        <!--用構造器注入參數-->
        <constructor-arg name="lastname" value="123"></constructor-arg>
    </bean>

10.2:實例工廠

工廠本身需要創建對象;工廠對象 = new 工廠類();工廠對象.方法();

public class PersonInstanceFactory {
    //創建實例工廠類
    public Person getPerson(String lastname){
        Person person = new Person();
        person.setLastName(lastname);
        person.setAge(18);
        return person;
    }
}
    <!--先創建工廠實例-->
    <bean id="personFactory" class="com.wkl.factory.PersonInstanceFactory"></bean>
    <!--創建bean實例,factory-bean指定工廠實例,factory-method指定工廠方法-->
    <bean id="person01" factory-bean="personFactory" factory-method="getPerson">
        <constructor-arg name="lastname" value="123"></constructor-arg>
    </bean>

10.3:使用FactoryBean工廠來創建實例

public class MyFactoryBean implements FactoryBean<Person> {
    /*
    * 當調用這個工廠的實例時,直接返回getObject下的實例*/
    @Override
    public Person getObject() throws Exception {
        Person person = new Person();
        return person;
    }

    @Override
    public Class<?> getObjectType() {
        return null;
    }
}

11:bean的生命週期

 <!--初始化用init-method方法,當構造器加載完後在執行init方法,bena銷燬前執行destroy-method方法-->
    <bean id="person01" class="com.wkl.bean.Person" init-method="myInit" destroy-method="getMaps">

    </bean>

lazy-init:"true" 這是bean標籤的屬性,表述該bean延遲初始化對象創建

default-lazy-init="true":這是beans的標籤屬性,表述所有的對象全部延遲初始化 

12:bean的後置處理器


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

/**
 * Description:
 * Date:       2020/6/21 - 下午 2:03
 * author:     wangkanglu
 * version:    V1.0
 */
public class MyBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("初始化前方法:bean:"+bean+"---beanname:"+beanName);
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("初始化後方法:bean:"+bean+"---beanname:"+beanName);
        return bean;
    }
}

必須在配置文件中實例化他

<bean class="com.wkl.bean.MyBeanPostProcessor"></bean>

13:ioc的自動裝配---Autowire

A中有屬性B(也是一個類),那麼在A的bean上的autowire含義如下:

  • autowire=byname:

以屬性名(b)去容器中找id爲(b)的容器,找到就賦值,找不到就算了

  • autowore=bytype:

以屬性類型(B)去找B類的組件,找到就賦值,如有多個就報錯,沒有就算了;

  • autowrie=constructor

根據B類的有參構造器裝配,依賴構造器注入;

先更具B類型進行裝配,沒有就根據id,

14:SPEL表達式

Spring Expression Language,Spring表達式語言,簡稱SpEL。支持運行時查詢並可以操作對象圖。

和JSP頁面上的EL表達式、Struts2中用到的OGNL表達式一樣,SpEL根據JavaBean風格的getXxx()setXxx()方法定義的屬性訪問對象圖,完全符合我們熟悉的操作習慣

基本語法

SpEL使用#{}作爲定界符,所有在大框號中的字符都將被認爲是SpEL表達式。

1:使用字面量

●整數:<property name="count" value="#{5}"/>
●小數:<property name="frequency" value="#{89.7}"/>
●科學計數法:<property name="capacity" value="#{1e4}"/>
●String類型的字面量可以使用單引號或者雙引號作爲字符串的定界符號
<property name=“name” value="#{'Chuck'}"/>
<property name='name' value='#{"Chuck"}'/>
●Boolean:<property name="enabled" value="#{false}"/>

2:引用其他bean

<bean id="emp04" class="com.atguigu.parent.bean.Employee">
	<property name="empId" value="1003"/>
	<property name="empName" value="Kate"/>
	<property name="age" value="21"/>
    //dept是其他bean的id
	<property name="detp" value="#{dept}"/>
</bean>

3:引用其他bean的屬性

<bean id="emp05" class="com.atguigu.parent.bean.Employee">
	<property name="empId" value="1003"/>
	<property name="empName" value="Kate"/>
	<property name="age" value="21"/>
	<property name="deptName" value="#{dept.deptName}"/>
</bean>

4:調用其他非靜態方法

<!-- 創建一個對象,在SpEL表達式中調用這個對象的方法 -->
<bean id="salaryGenerator" class="com.atguigu.spel.bean.SalaryGenerator"/>

<bean id="employee" class="com.atguigu.spel.bean.Employee">
	<!-- 通過對象方法的返回值爲屬性賦值 -->
	<property name="salayOfYear" value="#{salaryGenerator.getSalaryOfYear(5000)}"/>
</bean>

5:調用其他靜態方法

<bean id="employee" class="com.atguigu.spel.bean.Employee">
	<!-- 在SpEL表達式中調用類的靜態方法 -->
	<property name="circle" value="#{T(靜態類名).靜態方法名}"/>
</bean>

三:用註解來表達ioc

想用註解,必須導入aop包:spring-aop-5.2.6.RELEASE.jar

①普通組件:@Component

標識一個受Spring IOC容器管理的組件

②持久化層組件:@Repository

標識一個受Spring IOC容器管理的持久化層(數據庫層)組件

③業務邏輯層組件:@Service

標識一個受Spring IOC容器管理的業務邏輯層組件

④表述層控制器組件:@Controller

標識一個受Spring IOC容器管理的表述層控制器組件

⑤組件命名規則

[1]默認情況:使用組件的簡單類名首字母小寫後得到的字符串作爲bean的id

[2]使用組件註解的value屬性指定bean的id

注意:事實上Spring並沒有能力識別一個組件到底是不是它所標記的類型,即使將@Respository註解用在一個表述層控制器組件上面也不會產生任何錯誤,所以@Respository、@Service、@Controller這幾個註解僅僅是爲了讓開發人員自己明確當前的組件扮演的角色。

1:掃描組件:在xml中添加掃描包的路徑

1.1:掃描

<context:component-scan base-package="com.abc"/>
ApplicationContext ioc = new ClassPathXmlApplicationContext("beanXml/ioc3.xml");

    @Test
    public void test01(){
        Object personDao = ioc.getBean("person");
        Object personDao1 = ioc.getBean("person");
        System.out.println(""+personDao);
        System.out.println(""+personDao1);
    }

 [1]base-package屬性指定一個需要掃描的基類包,Spring容器將會掃描這個基類包及其子包中的所有類。

[2]當需要掃描多個包時可以使用逗號分隔。

[3]如果僅希望掃描特定的類而非基包下的所有類,可使用resource-pattern屬性過濾特定的類,

1.2:掃描排除

  • <context:include-filter>子節點表示要包含的目標類

注意:通常需要與use-default-filters屬性配合使用才能夠達到“僅包含某些組件”這樣的效果。即:通過將use-default-filters屬性設置爲false,禁用默認過濾器,然後掃描的就只是include-filter中的規則指定的組件了。

  • <context:exclude-filter>子節點表示要排除在外的目標類
  • component-scan下可以擁有若干個include-filter和exclude-filter子節點
  • 排除規則如下:

類別

示例

說明

annotation

com.XxxAnnotation

過濾所有標註了XxxAnnotation的類。這個規則根據目標組件是否標註了指定類型的註解進行過濾。

assignable

com.BaseXxx

過濾所有BaseXxx類的子類。這個規則根據目標組件是否是指定類型的子類的方式進行過濾。

aspectj

com.*Service+

所有類名是以Service結束的,或這樣的類的子類。這個規則根據AspectJ表達式進行過濾。

regex

com\.anno\.*

所有com.atguigu.anno包下的類。這個規則根據正則表達式匹配到的類名進行過濾。

custom

com.XxxTypeFilter

使用XxxTypeFilter類通過編碼的方式自定義過濾規則。該類必須實現org.springframework.core.type.filter.TypeFilter接口

 

2:改變註解的默認屬性

2.1:改變組件id

@Component(value = "person")
public class PersonDao {
}

2.1:改變默認單例

@Component(value = "person")
@Scope(value = "prototype")//設置爲多實例
public class PersonDao {
}

3:@Autowired --- 自動注入

3.1:Autowired的使用

@Component
public class CarDao {

    public void getCar(){
        System.out.println("買了一輛車。。。");
    }
}
@Component(value = "person")
public class PersonDao {


    @Autowired
    public CarDao carDao;

    public void buyCar(){
        carDao.getCar();
    }
}
ApplicationContext ioc = new ClassPathXmlApplicationContext("beanXml/ioc3.xml");

    @Test
    public void test01(){
        PersonDao personDao = ioc.getBean("person", PersonDao.class);
        personDao.buyCar();
    }

3.2:Autowired的原理

當有Autowired標註的屬性時,

   @Autowired
    public CarDao carDao;

先按照類的類型(CarDao )去容器中找對應的組件,

  1.      找到就賦值,
  2.      找不到報異常
  3.       找到多個的話

                   就按照屬性名(carDao )作爲id去容器中找

                    如果屬性名也沒匹配上,就報異常,也可以通過@Qualifier來加載指定id的bean

    @Qualifier("bean的id")
    @Autowired
    public CarDao carDao;

還可以通過@Autowired(required = false)設置爲false後,標識裝配不上就算了,將對象置爲null;

3.3:給方法上注入@Autowired

這個方法也會在bean創建時自動運行

這個方法的所有參數也會自動注入

注入規則和上邊一樣

    @Autowired
    public void buyCar(@Qualifier("carDao") CarDao carDao){
        carDao.getCar();
    }

3.4:@Resource和@Autowired的區別

他們兩個都能自動裝配;

@Resource是j2ee的標準,擴展性更強,在EJB中也能使用;

@Autowired是Spring自己的框架,離開了Spring就沒用了;

 

4:使用spring的單元測試

導入spring的test包

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.2.6.RELEASE</version>
        </dependency>
@ContextConfiguration(locations = "classpath:beanXml/ioc3.xml")
@RunWith(SpringJUnit4ClassRunner.class)
public class TestZJ {


//    ApplicationContext ioc = new ClassPathXmlApplicationContext("beanXml/ioc3.xml");

    @Autowired
    PersonDao personDao;

    @Test
    public void test01(){
        System.out.println(""+personDao);
    }
}

5:泛型依賴注入:

 

 

 

 

當注入一個組件的時候,他的泛型也是參考選項;

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

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