天天看點

Spring5基礎(2)——Spring IoC控制反轉(基礎)

此部落格為學習筆記,記錄下來怕自己後面學着學着忘記了。

Spring IoC控制反轉概念

簡書内容同步,id同名,簡書本文連結

Inversion of Control(IoC)控制反轉:是一種通過描述(xml配置檔案或注解),并通過第三方去産生或擷取特定對象的方式。

實作控制反轉的是:IoC容器。

操作方法是:依賴注入。

控制反轉的結果是對象執行個體不再有調用者建立,而是由Spring容器來建立,即控制權由調用者轉移到Spring容器。

Spring的依賴注入:Spring容器負責将被依賴的對象(需要的對象執行個體),指派給調用者的成員變量,相當于為調用者注入了它所依賴的執行個體。

為什麼要使用Spring IoC,作用是什麼?

使用Spring IoC的作用是:消減程式間的耦合問題。

舉個栗子:比如在B類中需要一個A類的執行個體對象,在B類中若使用New關鍵字來建立A類執行個體,按如下所示:

package com.lipiao.demo;

public class A {
    String name;
    public void setName(String name) {
        this.name = name;
    }
}
           
package com.lipiao.demo;

public class B {

    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        //修改前
        A a=new A();
        a.setName("A1");
        System.out.println(a.name);
    }
}
           

運作效果就是控制台輸出A1:

Spring5基礎(2)——Spring IoC控制反轉(基礎)

實際開發中肯定不止2個類,随着邏輯處理越來越多,這樣的處理方式會使不同的類之間耦合越來越嚴重,代碼的維護會比較困難。

耦合:程式間的依賴關系

包括:①類之間的依賴 ②方法之間的依賴

弊端 獨立性很差

解耦:盡可能降低程式間的依賴關系(經可能是因為有的耦合沒法避免)

實際開發中應該做到:編譯期間不依賴,運作時才依賴

解耦思路:

第一步:使用反射來建立對象,而避免使用new關鍵字

第二步:通過讀取配置檔案來擷取要建立的對象權限定類名

使用java的反射特性來修改上面的B類中的代碼,假設A類所在包路徑為:com.lipiao.demo.A

package com.lipiao.demo;
public class B {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        //修改前
        A a=new A();
        a.setName("A1");
        System.out.println(a.name);
        
        //使用反射
        Class<?> classA = Class.forName("com.lipiao.demo.A");
        A a2=(A)classA.newInstance();
        a2.setName("A2");
        System.out.println(a2.name);
    }
}
           

運作效果如下:

Spring5基礎(2)——Spring IoC控制反轉(基礎)

這樣New關鍵字就沒有啦,初步解耦就完成啦。

更多java反射特性的使用,本文不多撰寫啦,我找了一片部落格:Java的進階特性 - 反射

但是以上代碼還沒有做到編譯期間不依賴,運作時才依賴。

進一步解耦就要使用Spring IoC控制反轉啦,通過依賴注入,讓IoC容器幫我們建立執行個體對象。

Spring IoC容器的基本使用

實作控制反轉的是:IoC容器。

Spring IoC容器的設計基于兩個接口:

①BeanFactory接口,使用絕對路徑

//3.使用Spring  IoC容器 BeanFactory接口 使用絕對路徑
        BeanFactory beanFactory = new XmlBeanFactory(new FileSystemResource
                ("C:\\Users\\11092\\IdeaProjects\\javaEE\\src\\main\\resources\\META-INF\\applicationContext.xml"));
        //通過容器建立A類執行個體,xml中id為A,getBean傳入A
        A a3 = (A) beanFactory.getBean("A");
        System.out.println(a3.name);
           

applicationContext.xml

<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="A" class="com.lipiao.demo.A">
        <property name="name" value="A3"></property>
    </bean>
</beans>
           
Spring5基礎(2)——Spring IoC控制反轉(基礎)

②ApplicationContext接口

1.使用ClassPathXmlApplicationContext建立ApplicationContext接口執行個體,使用相對路徑(resources根目錄)

//4.使用Spring  IoC容器 ApplicationContext接口
        //有3種建立ApplicationContext接口的方式:

        //4.1 ClassPathXmlApplicationContext 使用相對路徑(resources根目錄)
        ApplicationContext applicationContext4_1 =
                new ClassPathXmlApplicationContext("META-INF/applicationContext.xml");
        A a4_1= (A) applicationContext4_1.getBean("A4_1");
        System.out.println(a4_1.name);
           

applicationContext.xml

<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="A4_1" class="com.lipiao.demo.A">
        <property name="name" value="A4_1"></property>
    </bean>
</beans>
           

會有兩條紅色的提示資訊,一條是重新整理ClassPathXmlApplicationContext,一條是從xml配置檔案中加載對應的bean檔案

運作結果:控制台輸出A4_1

Spring5基礎(2)——Spring IoC控制反轉(基礎)

2.使用FileSystemXmlApplicationContext建立ApplicationContext接口執行個體,使用絕對路徑

//4.2 FileSystemXmlApplicationContext 使用絕對路徑
        ApplicationContext applicationContext4_2= new FileSystemXmlApplicationContext(
                "C:\\Users\\11092\\IdeaProjects\\javaEE\\src\\main\\resources\\META-INF\\applicationContext.xml");
        A a4_2= (A) applicationContext4_2.getBean("A4_2");
        System.out.println(a4_2.name);
           

applicationContext.xml

<bean id="A4_2" class="com.lipiao.demo.A">
        <property name="name" value="A4_2"></property>
    </bean>
           

會有兩條紅色的提示資訊,一條是重新整理ClassPathXmlApplicationContext,一條是從xml配置檔案中加載對應的bean檔案

運作結果:控制台輸出A4_2

Spring5基礎(2)——Spring IoC控制反轉(基礎)

3.使用web伺服器執行個體化ApplicationContext容器

一般使用基于org.springframework.web.context.ContextLoaderListener的實作方式,在web.xml檔案中添加:

<context-parm>
   <param-name>contextConfigLocation</param-name>
   <param-value>
      classpath:applicationContext.xml
   </param-value>
</context-parm>

<listener>
   <listener-class>
       org.springframework.web.context.ContextLoaderListener
   </listener-class>
</listener>
           

Spring IoC容器的依賴注入類型

①構造方法注入

Spring架構可以采用java的反射機制,通過構造方法完成依賴注入。

以下面這個C類為例:

package com.lipiao.demo;
//Spring  IoC容器依賴注入 1.構造方法注入
public class C {
    String name;
    public C(String name) {
        this.name = name;
    }
}
           

applicationContext.xml中

<bean id="C5_1" class="com.lipiao.demo.C">
        <constructor-arg index="0" value="C_strName_constructor"/>
    </bean>
           

index用于定義參數的位置,value表示參數為常數,若為執行個體引用,将value替換為ref

運作效果:

會有兩條紅色的提示資訊,一條是重新整理ClassPathXmlApplicationContext,一條是從xml配置檔案中加載對應的bean檔案

控制台列印C_strName_constructor

資訊: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@7d907bac: startup date [Wed Jul 17 21:12:40 CST 2019]; root of context hierarchy
七月 17, 2019 9:12:40 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
資訊: Loading XML bean definitions from class path resource [META-INF/applicationContext.xml]
C_strName_constructor
           

②使用屬性的setter方法注入(這是最主流的注入方式)

使用setter注入方法和構造方法注入類似,剛剛在介紹Spring IoC容器的基本使用的案例都是使用屬性setter注入的。

還是看個例子吧,同樣是上面的C類,修改C類代碼,添加setter方法,删掉構造方法:

package com.lipiao.demo;
//Spring  IoC容器依賴注入 
// 1.構造方法注入
// 2.setter方法注入
public class C {
    String name;
    //構造方法注入
//    public C(String name) {
//        this.name = name;
//    }
    //setter方法注入
    public void setName(String name) {
        this.name = name;
    }
}
           

修改applicationContext.xml配置資訊:

<bean id="C5_2" class="com.lipiao.demo.C">
        <property name="name" value="C_strName_setter"/>
    </bean>
           

運作效果:

會有兩條紅色的提示資訊,一條是重新整理ClassPathXmlApplicationContext,一條是從xml配置檔案中加載對應的bean檔案

控制台列印C_strName_setter

資訊: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@148080bb: startup date [Wed Jul 17 21:29:37 CST 2019]; root of context hierarchy
七月 17, 2019 9:29:37 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
資訊: Loading XML bean definitions from class path resource [META-INF/applicationContext.xml]
C_strName_setter
           

對于Spring Bean的更多細節,将在下一篇部落格中提及。

繼續閱讀