Spring框架研究總結之IOC

Spring框架研究總結之IOC

 

Spring是一個開源的企業應用框架,是一個分層架構,由7個定義穩定的模塊所組成,而所有的模塊都是在覈心容器基礎上搭建;其體系本身提供了強大的IOC(控制反轉)、AOP(面向切面)以及DI(依賴注入)等較顯著的功能,那麼下面就來詳細介紹下Spring框架的模塊組成及相關特點。

 

l   框架結構

l   依賴注入

l   控制反轉

 

一、框架結構

Spring是一個分層架構,目前由7個穩定的模塊所組成,而其它所有的模塊都構建於核心容器之上,而核心容器負責Bean的創建、配置及管理Bean的方式,具體結構圖如下:

正如上面的結構圖所示,組成Spring框架的每個模塊都可以單獨存在,或者與其它多個模塊結合使用,具體每個模塊的功能如下:

1、Spring Core

該模塊提供了Spring框架的基本功能,其主要的組件是BeanFactory,該組件是由工廠模式實現,並且使用控制反轉(IOC)模式將應用程序的配置和依賴規範與實際應用程序分開來。

 

2、Spring Context

該模塊向Spring框架提供上下文配置信息,該配置信息包括但不限於:EJB、JNDI、Main、校驗、調度及國際化功能。

 

3、Spring ORM

Spring 框架插入了若干個 ORM 框架,從而提供了 ORM 的對象關係工具,其中包括 JDO、Hibernate 和iBatis SQL Map。所有這些都遵從 Spring 的通用事務和 DAO 異常層次結構。

 

4、Spring DAO

JDBC DAO 抽象層提供了有意義的異常層次結構,可用該結構來管理異常處理和不同數據庫供應商拋出的錯誤消息。異常層次結構簡化了錯誤處理,並且極大地降低了需要編寫的異常代碼數量(例如打開和關閉連接)。Spring DAO 的面向 JDBC 的異常遵從通用的 DAO 異常層次結構。

 

5、Spring WEB

Web 上下文模塊建立在應用程序上下文模塊之上,爲基於 Web 的應用程序提供了上下文。所以,Spring 框架支持與 Jakarta Struts 的集成。Web 模塊還簡化了處理多部分請求以及將請求參數綁定到域對象的工作。

 

6、Spring WEB MVC

MVC 框架是一個全功能的構建 Web 應用程序的 MVC 實現。通過策略接口,MVC 框架變成爲高度可配置的,MVC 容納了大量視圖技術,其中包括 JSP、Velocity、Tiles、iText和 POI。

 

最後,Spring 框架的功能可以用在任何 J2EE 服務中,大多數功能也適用於不受管理的環境。而Spring 的核心是:支持不綁定到特定 J2EE 服務的可重用業務和數據訪問對象,這樣的對象可以在不同 J2EE 環境 (Web 或 EJB)、獨立應用程序、測試環境之間重用。

 

二、依賴注入(DI)

什麼是依賴注入?我的理解就是當類A的一個對象必須引用另一個類B的對象才能完成其所需功能時,我們稱A和B兩者間存在依賴關係,如果類A只是通過類B實現的接口來引用類B的對象,我們說這兩個類是鬆耦合的,而Spring的DI模式通過一種靈活的方式將類B對象賦值給了類A,而類A不需要知道類B的存在,這種方式我們稱之爲依賴注入。至於如何把類B的對象注入到類A中,實際是使用了Java的反射機制來實現,當然這些不需要我們操心,一切全交給了Spring自動完成。下面分別介紹,並舉例驗證,最後以一個Java項目爲例結合DI、IOC的使用。

 

1、注入內容

在Spring中,我們注入的內容稱之爲Bean,也就是JavaBean,而在MVC架構中,Bean充當model層,在一般程序中,我們稱之爲數據層,也就是用來存儲數據的屬性和一些行爲,然後提供屬性的get/set操作。

 

2、Setter注入

Setter注入就是根據Bean的set方法來注入另一個依賴的對象,具體如下:

 

A、Bean準備

Person類:

public class Person {

      private String name;

      private String address;

      private int age;

     

      public String getName() {

            return name;

      }

 

      public void setName(String name) {

            this.name = name;

      }

 

      public String getAddress() {

            return address;

      }

 

      public voidsetAddress(String address) {

            this.address = address;

      }

 

      public int getAge() {

            return age;

      }

 

      public void setAge(int age) {

            this.age = age;

      }

 

      @Override

      public String toString() {

            return "Person [name=" + name + ", address=" + address + ", age=" + age

                        +"]";

      }

}

 

Customer類:

public class Customer {

      private Person person = null;

      public Person getPerson() {

            return person;

      }

 

      public void setPerson(Personperson) {

            this.person = person;

      }

 

      @Override

      public String toString() {

            return "Customer [person=" + person + "]";

      }

}

 

B、XML注入

<bean id="CustomerBean"class="com.spring.beandi.bean.Customer" >

          <property name="person"ref="PersonBean" />

</bean>

<bean id="PersonBean"class="com.spring.beandi.bean.Person" >

            <property name="name"value="cwteam" />

            <property name="address"value="雲端科盟999" />

            <property name="age"value="66" />

</bean>

 

注意:

這裏爲Person類中的屬性name、address及age給予默認值,也可以在代碼實現中動態賦值,這樣更加清楚的展示依賴注入的原理。

 

C、如何使用

由於創建的是Java項目,所以需要使用org.springframework.context中的ConfigurableApplicationContext完成xml配置文件加載到Spring容器。

 

具體如下使用:

public class App {

      private staticConfigurableApplicationContext context;

 

      public static void main(String[] args) throws IOException, JAXBException {

            context = new ClassPathXmlApplicationContext("com/spring/beandi/config/applicationContext.xml");

           

            Customerc = (Customer) context.getBean("CustomerBean");

            log(c);          

            context.close();

      }

     

      static void log(Object obj) {

            System.out.println(obj.toString());

      }

}

 

運行結果顯示:

 

3、構造注入

構造注入,也就是根據Bean的構造函數依賴注入另一個對象,具體如下:

 

A、Bean準備

Person類:

public class Person {

      private String name;

      private String address;

      private int age;

     

      public String getName() {

            return name;

      }

 

      public void setName(String name) {

            this.name = name;

      }

 

      public String getAddress() {

            return address;

      }

 

      public voidsetAddress(String address) {

            this.address = address;

      }

 

      public int getAge() {

            return age;

      }

 

      public void setAge(int age) {

            this.age = age;

      }

 

      @Override

      public String toString() {

            return "Person [name=" + name + ", address=" + address + ", age=" + age

                        +"]";

      }

}

 

Customer類:

public class Customer {

      private Person person = null;

     

      public Customer(Person person) {

            this.person = person;

      }

 

      public Person getPerson() {

            return person;

      }

 

      @Override

      public String toString() {

            return "Customer [person=" + person + "]";

      }

}

 

B、XML配置

<bean id="CustomerBean"class="com.spring.beandi.bean.Customer" >

            <constructor-arg>

                  <bean class="com.spring.beandi.bean.Person">

                        <property name="name"value="jackup" />

                        <property name="address"value="雲端科盟666" />

                        <property name="age"value="33" />

                  </bean>

            </constructor-arg>

</bean>

 

注意:

這裏使用<constructor-arg/>標籤,直接將Person嵌入其中,並指定默認的屬性值,接下來Spring容器便會自動實例化。

 

C、如何使用

public class App {

      private staticConfigurableApplicationContext context;

 

      public static void main(String[] args) throws IOException, JAXBException {

            context = new ClassPathXmlApplicationContext("com/spring/beandi/config/applicationContext2.xml");

           

            Customerc = (Customer) context.getBean("CustomerBean");

            log(c);

                       

            context.close();

      }

     

      static void log(Object obj) {

            System.out.println(obj.toString());

      }

}

 

運行結果顯示:

 

 

三、控制反轉(IOC)

IOC容器是具備依賴注入功能的容器,該依賴注入功能是藉助於DI機制實現,並且IOC容器也負責存儲實例、實例化、定位、配置應用程序中的對象以及建立對象間的關係,而Spring中的所有實例對象都存放在IOC這個容器中,由Spring自動搜尋和分配對應的實例,某種意義上說,IOC與DI很相似,可以理解爲DI是IOC功能的子集,這是個人理解,如有異議請在評論中言明探討,在下面就以一個簡單的例子來說明!

 

1、Bean準備

HelloWorld接口:

public interfaceHelloWorld {

      void printMsg(String msg);

}

 

HelloWorldImpl類:

public class HelloWorldImpl implements HelloWorld {

 

      @Override

      public void printMsg(String msg) {

            System.out.println("Hello:" + msg);

      }

}

 

2、XML注入

     <bean id="helloService"class="com.spring.helloworld.Impl.HelloWorldImpl" />

 

注意:

這裏指定了實現接口的類的類路徑,Spring容器通過id值獲取並實例化這個類對象。

 

3、如何使用

public class App {

      private staticApplicationContext context = null;

 

      public static void main(String[] args) {

            // 讀取配置文件實例化一個IOC容器

            context = new ClassPathXmlApplicationContext("com/spring/helloworld/applicationContext.xml");

            // 從容器中獲取Bean,注意此處是面向接口編程

            HelloWorldhelloService = context.getBean("helloService",HelloWorld.class);

        // 執行業務邏輯

            helloService.printMsg("this is my blog of springframework,you know?");      

      }

}

 

運行結果顯示:

 

4、scope使用

默認情況下,bean工廠生產的實例爲單例模式對象,也就是隻有一個類並且該類可以被其它需要的實例所調用,並不創建一個新的實例對象,此種對象稱之爲“無狀態”對象實例;而“有狀態”的實例,指的是隨着擁有該狀態實例的對象生命消失時,其用用的狀態實例也自然消失,而“無狀態”正好反之。所以,如果我們想在Spring中創建一個有狀態的實例對象,那麼我們可以在定義Bean時,爲其指定關鍵字scope,內容爲prototype即可,具體如下代碼:

<bean id="PersonBean"class="com.spring.beandi.bean.Person" scope="prototype" >

          <property name="name"value=" jackup " />

          <property name="address"value="雲端科盟666" />

          <property name="age"value="33" />

     </bean>

 

5、集合屬性

在Spring中,我們不僅可以實例化基本的數據類型屬性,還可以實例化集合屬性,比如:List、Set、Map以及Properties類型數據,具體如下:

Bean對象DataCollection:

public class DataCollection {

      private List<Object> lists;

      private Set<Object> sets;

      private Map<Object, Object> maps;

      private Properties pros;

 

      public List<Object> getLists() {

            return lists;

      }

 

      public voidsetLists(List<Object> lists) {

            this.lists = lists;

      }

 

      public Set<Object> getSets() {

            return sets;

      }

 

      public voidsetSets(Set<Object> sets) {

            this.sets = sets;

      }

 

      public Map<Object, Object> getMaps() {

            return maps;

      }

 

      public voidsetMaps(Map<Object, Object> maps) {

            this.maps = maps;

      }

 

      public Properties getPros() {

            return pros;

      }

 

      public voidsetPros(Properties pros) {

            this.pros = pros;

      }

 

      @Override

      public String toString() {

            return "Customer2 [lists=" + lists + ", sets=" + sets + ", maps="

                        +maps + ", pros=" + pros + "]";

      }

}

 

A、List

            <property name="lists">

                  <list>

                        <value>1</value>

                        <ref bean="PersonBean"/>

                        <bean class="com.spring.beandi.bean.Person">

                              <property name="name"value="Kitty" />

                              <property name="address"value="雲端科盟666" />

                              <property name="age"value="25" />

                        </bean>

                  </list>

            </property>

 

注意:

lists:對應Bean對象中的屬性lists,必須一致否則找不到;

<list/>:標籤內可以存放多種類型的內容,與Java中List使用相同,也可以引用已經存在的Bean對象,也可以使用<bean/>標籤直接在該屬性中加入屬性字段即可;

 

B、Set

<property name="sets">

                  <set>

                        <value>1</value>

                        <ref bean="PersonBean"/>

                        <bean class="com.spring.beandi.bean.Person">

                              <property name="name"value="Jackey " />

                              <property name="address"value="雲端科盟666" />

                              <property name="age"value="30" />

                        </bean>

                  </set>

            </property>

 

注意:

與List使用方式相同,不同的是不能存在重複的數據;

 

C、Map

<property name="maps">

                  <map>

                        <entry key="K1"value="1" />

                        <entry key="K2"value-ref="PersonBean" />

                        <entry key="K3">

                              <bean class="com.spring.beandi.bean.Person">

                                    <property name="name"value="Mayper " />

                                    <property name="address"value="雲端科盟666" />

                                    <property name="age"value="31" />

                              </bean>

                        </entry>

                  </map>

            </property>

 

注意:

存放鍵-值形式數據,若加入對象實例,需要放在<entry />標籤內使用。

 

最後,整體的文件如下:

<?xml version="1.0"encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

      xsi:schemaLocation="http://www.springframework.org/schema/beans

      http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">

      <bean id="dataCollectionBean"class="com.spring.beandi.bean.DataCollection">

            <!-- java.util.List -->

            <property name="lists">

                  <list>

                        <value>1</value>

                        <ref bean="PersonBean"/>

                        <bean class="com.spring.beandi.bean.Person">

                              <property name="name"value="Kitty" />

                              <property name="address"value="雲端科盟666" />

                              <property name="age"value="25" />

                        </bean>

                  </list>

            </property>

            <!-- java.util.Set -->

            <property name="sets">

                  <set>

                        <value>1</value>

                        <ref bean="PersonBean"/>

                        <bean class="com.spring.beandi.bean.Person">

                              <property name="name"value="Jackey " />

                              <property name="address"value="雲端科盟666" />

                              <property name="age"value="30" />

                        </bean>

                  </set>

            </property>

            <!-- java.util.Map -->

            <property name="maps">

                  <map>

                        <entry key="K1"value="1" />

                        <entry key="K2"value-ref="PersonBean" />

                        <entry key="K3">

                              <bean class="com.spring.beandi.bean.Person">

                                    <property name="name"value="Mayper " />

                                    <property name="address"value="雲端科盟666" />

                                    <property name="age"value="31" />

                              </bean>

                        </entry>

                  </map>

            </property>

      </bean>

      <bean id="PersonBean"class="com.spring.beandi.bean.Person">

            <property name="name"value="David" />

            <property name="address"value="上海世博園-中國館" />

            <property name="age"value="30" />

      </bean>

</beans>

 

 

6、日期處理

這裏以處理簡單的日期爲例,即使用java.text.SimpleDateFormat來格式化日期時間,具體的XML如下:

<bean id="dateFormat"class="java.text.SimpleDateFormat" >

            <constructor-arg value="yyyy-M-d"/>

      </bean>

     

      <bean id="dateformat2"class="com.spring.beandi.bean.DateFormatDemo">

            <property name="date">

                  <bean factory-bean="dateFormat"factory-method="parse">

                        <constructor-arg value="2016-08-09"/>

                  </bean>

            </property>

      </bean>

 

7、類的繼承

A、Bean準備

父類:

public class Father {

      private String name;

      private int age;

      private String address;

 

      public String getName() {

            return name;

      }

 

      public void setName(String name) {

            this.name = name;

      }

 

      public int getAge() {

            return age;

      }

 

      public void setAge(int age) {

            this.age = age;

      }

 

      public String getAddress() {

            return address;

      }

 

      public voidsetAddress(String address) {

            this.address = address;

      }

 

      @Override

      public String toString() {

            return "Father [name=" + name + ", age=" + age + ", address=" + address

                        +"]";

      }

}

 

子類:

public class Child extends Father {

      private String name;

      private int age;

      private String address;

      private String email;

 

      public String getName() {

            return name;

      }

 

      public void setName(String name) {

            this.name = name;

      }

 

      public int getAge() {

            return age;

      }

 

      public void setAge(int age) {

            this.age = age;

      }

 

      public String getAddress() {

            return address;

      }

 

      public voidsetAddress(String address) {

            this.address = address;

      }

 

      public String getEmail() {

            return email;

      }

 

      public void setEmail(String email) {

            this.email = email;

      }

 

      @Override

      public String toString() {

            return "Child [name=" + name + ", age=" + age + ", address=" + address

                        +", email=" + email + "]";

      }

}

 

B、XML準備

<bean id="father"class="com.spring.beandi.bean.Father" abstract="false">

            <property name="name"value="Mr Jacky" />

      </bean>

     

      <bean id="child"class="com.spring.beandi.bean.Child" parent="father">

            <property name="age"value="33" />

            <property name="address"value="雲端科盟686" />

            <property name="email"value="[email protected]" />

      </bean>

 

C、如何使用

public class App {

      private staticConfigurableApplicationContext context;

 

      public static void main(String[] args) throws IOException, JAXBException {

            context = new ClassPathXmlApplicationContext("com/spring/beandi/config/applicationContext4.xml");

                 

            Fatherfather = (Father) context.getBean("father");

            log(father);

            Childchild = (Child) context.getBean("child");

            log(child);

 

            context.close();

      }

     

      static void log(Object obj) {

            System.out.println(obj.toString());

      }

}

 

結果顯示:

 

8、方法調用

在Spring中,允許在Bean中自定義執行的方法,待該Bean被實例化時,可以調用init-method指定的Bean方法,而Bean結束銷燬時,則調用destroy-method指定的Bean方法,具體如下:

A、Bean準備

public class Person2 {

      private String name;

      private String address;

      private int age;

     

      // Bean初始化方法

      public void init() throws Exception {

            System.out.println("Spring initialize method is callingnow!");

      }

     

      // Bean銷燬方法

      public void cleanup() throws Exception {

            System.out.println("Spring destroy method is callingnow!");

      }

 

      public String getName() {

            return name;

      }

 

      public void setName(String name) {

            this.name = name;

      }

 

      public String getAddress() {

            return address;

      }

 

      public voidsetAddress(String address) {

            this.address = address;

      }

 

      public int getAge() {

            return age;

      }

 

      public void setAge(int age) {

            this.age = age;

      }

 

      @Override

      public String toString() {

            return "Person2 [name=" + name + ", address=" + address + ", age="

                        +age + "]";

      }

}

 

B、XML準備

<bean id="PersonBean"class="com.spring.beandi.bean.Person2"  init-method="init"destroy-method="cleanup"  >

            <property name="name"value="jacky" />

            <property name="address"value="雲端科盟686" />

            <property name="age"value="32" />

      </bean>

 注意:

其實很簡單,只需要在Bean的xml配置中,添加init-method和destroy-method標籤即可,待bean被實例化及生命週期觸發執行。

 

C、如何使用

ConfigurableApplicationContext context = new ClassPathXmlApplicationContext("com/spring/beandi/config/applicationContext7.xml");

Person2 p = (Person2) context.getBean("PersonBean");

log(p);

 

結果顯示:

 

注意:

從上圖可以知道,先執行的是init-method指定的方法,再執行我們打印的日誌方法,最後,因爲我們調用了context.close()方法,所以Bean生命週期結束,所以調用了destroy-method指定的方法了。

 

 

 

 

 

好了,Spring框架之IOC就介紹到這裏,由於作者水平有限,如有問題請在評論發言或是QQ羣討論,謝謝。

 

 

 

技術討論羣:

245389109(新)

 

發佈了132 篇原創文章 · 獲贊 164 · 訪問量 47萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章