大部分的企業架構都基於Spring框架。它的成功來自於理念,而不是技術,它最為核心的理念是IoC(控制反轉)和AOP(面向切面編程),其中IoC是Spring的基礎,而AOP則是其重要的功能,最為典型的當屬數據庫事務的使用。
Spring的概述
Spring提供了以下策略:
•對於POJO的潛力開發,提供輕量級和低侵入的編程,可以通過配置(XML、注解等)來擴展POJO的功能,通過依賴注入的理念去擴展功能,建議通過接口編程,強調OOD的開發模式理念,降低系統耦合度,提高系統可讀性和可擴展性。
•提供切面編程,尤其是把企業的核心應用——數據庫應用,通過切面消除了以前復雜的try...catch...finally...代碼結構,使得開發人員能夠把精力更加集中於業務開發而不是技術本身,也避免了try...catch...finally語句的濫用。
•為了整合各個框架和技術的應用,Spring提供了模板類,通過模板可以整合各個框架和技術,比如支持Hibernate開發的HibernateTemplate、支持MyBatis開發的SqlSessionTemplate、支持Redis開發的RedisTemplate等,這樣就把各種企業用到的技術框架整合到Spring中,提供了統一的模板,從而使得各種技術用起來更簡單。
Spring IoC概述
控制反轉是一個比較抽象的概念,我們舉例說明。在實際生活中,人們要用到一樣東西時,人們的基本想法是找到東西,比如想喝杯橙汁,在沒有飲品店的日子里,最直觀的做法是,要買果汁機、橙子,准備開水。請注意這是你自己“主動”創造的過程,也就是一杯橙汁需要主動創造。然而到了今時今日,由於飲品店的盛行,已經沒有必要自己去榨橙汁了。想喝橙汁的想法一出現,第一個想法是找到飲品店的聯系方式,通過電話、微信等渠道描述你的需要、地址、聯系方式等,下訂單等待,過會就會有人送上橙汁了。請注意你並沒有“主動”創造橙汁,也就是橙汁是由飲品店創造的,而不是你,但是也完全達到了你的要求。
為了更好地闡述上面的抽象描述,我們用Java代碼的形式模擬主動創建和被動創建的過程。
代碼清單:攪拌機和果汁生成器
/** * 攪拌機 */ public class Blender { /** * 攪拌 * * @param water 水描述 * @param fruit 水果描述 * @param sugar 糖描述 * @return 果汁 */ public String mix(String water, String fruit, String sugar) { String juice = "這是一杯由液體:" + water + "\n 水果:" + fruit + "\n糖量:" + sugar + "\n組成的果汁"; return juice; } } /** * 果汁生成器 */ public class JuiceMaker { private Blender blender = null;//攪拌機 private String water;//水描述 private String fruit;//水果 private String sugar;//糖分描述 /** * 果汁生成 */ public String makeJuice() { blender = new Blender(); return blender.mix(water, fruit, sugar); } /**** setter and getter ****/ }
被動創建對象
代碼清單:果汁制造器和果汁描述
/** * 果汁制造器和果汁描述 */ public class JuiceMaker2 { private String beverageShop = null; private Source source = null; public String makeJuice() { String fileEncoding = System.getProperty("file.encoding");//查看系統默認編碼方式 System.out.println("fileEncoding:" + fileEncoding); String juice = "這是由" + beverageShop + "飲品店,提供的" + source.getSize() + source.getSugar() + source.getFruit(); return juice; } /**** setter and getter ****/ } public class Source { private String fruit;//類型 private String sugar;//糖分描述 private Integer size;//大小杯 /**** setter and getter ****/ }
Spring IoC闡述
有了上面的實例,下面我們闡述控制反轉的概念:控制反轉是一種通過描述(在Java中可以是XML或者注解)並通過第三方去產生或獲取特定對象的方式。
在Spring中實現控制反轉的是IoC容器,其實現方法是依賴注入(Dependency Injection,DI)。正如上述的例子,果汁制造器依賴於飲品店和訂單去制造果汁的,而飲品店是別人去創造的,我們只需要知道它能生產果汁就可以了,並不需要去理解如何創建果汁。
Spring IoC容器
Spring IoC容器的作用,它可以容納我們所開發的各種Bean,並且我們可以從中獲取各種發布在Spring IoC容器里的Bean,並且通過描述可以得到它。
Spring IoC容器的設計
Spring IoC容器的設計主要是基於BeanFactory和Applica-tionContext兩個接口,其中ApplicationContext是BeanFactory的子接口之一,換句話說BeanFactory是Spring IoC容器所定義的最底層接口,而ApplicationContext是其高級接口之一,並且對BeanFactory功能做了許多有用的擴展,所以在絕大部分的工作場景下,都會使用ApplicationContext作為Spring IoC容器
代碼清單:spring-cfg.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-4.0.xsd"> <bean id="source" class="com.ssm.chapter9.pojo.Source"> <property name="fruit" value="橙汁"/> <property name="sugar" value="少糖"/> <property name="size" value="3"/> </bean> <bean id="juiceMaker2" class="com.ssm.chapter9.pojo.JuiceMaker2"> <property name="beverageShop" value="貢茶"/> <property name="source" ref="source"/> </bean> </beans>
ApplicationContext ctx = new ClassPathXmlApplicationContext("ssm/chapter9/spring-cfg.xml"); JuiceMaker2 juiceMaker2 = (JuiceMaker2) ctx.getBean("juiceMaker2"); System.out.println(juiceMaker2.makeJuice());
Spring IoC容器的初始化和依賴注入
這里需要注意的是Bean的初始化和依賴注入在Spring IoC容器中是兩大步驟,它是在初始化之后,才會進行依賴注入。Bean的初始化分為3步:
(1)Resource定位,這步是Spring IoC容器根據開發者的配置,進行資源定位,在Spring的開發中,通過XML或者注解都是十分常見的方式,定位的內容是由開發者所提供的。
(2)BeanDefinition的載入,這個過程就是Spring根據開發者的配置獲取對應的POJO,用以生成對應實例的過程。
(3)BeanDefinition的注冊,這個步驟就相當於把之前通過BeanDefinition載入的POJO往Spring IoC容器中注冊,這樣就可以使得開發和測試人員都可以通過描述從中得到Spring IoC容器的Bean了。
做完了這3步,Bean就在Spring IoC容器中得到了初始化,但是沒有完成依賴注入,也就是沒有注入其配置的資源給Bean,那么它還不能完全使用。對於依賴注入,Spring Bean還有一個配置選項——lazy-init,其含義就是是否初始化Spring Bean。在沒有任何配置的情況下,它的默認值為default,實際值為false,也就是Spring IoC默認會自動初始化Bean。如果將其設置為true,那么只有當我們使用Spring IoC容器的getBean方法獲取它時,它才會進行初始化,完成依賴注入。
Spring Bean的生命周期
SpringIoC容器的本質目的就是為了管理Bean。對於Bean而言,在容器中存在其生命周期,它的初始化和銷毀也需要一個過程,在一些需要自定義的過程中,我們可以插入代碼去改變它們的一些行為,以滿足特定的需求,這就需要使用到Spring Bean生命周期的知識了。
生命周期主要是為了了解Spring IoC容器初始化和銷毀Bean的過程,通過對它的學習就可以知道如何在初始化和銷毀的時候加入自定義的方法,以滿足特定的需求。
BeanPostProcessor接口則是針對所有Bean而言的;接口DisposableBean則是針對Spring IoC容器本身。當一個Bean實現了上述的接口,我們只需要在Spring IoC容器中定義它就可以了,Spring IoC容器會自動識別。
代碼清單:BeanPostProcessor的實現類
import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; public class BeanPostProcessorImpl implements BeanPostProcessor { // @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println("【" + bean.getClass().getSimpleName() + "】對象" + beanName + "開始實例化"); return bean; } // @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println("【" + bean.getClass().getSimpleName() + "】對象" + beanName + "實例化完成"); return bean; } }
代碼清單:DisposableBean實現類
import org.springframework.beans.factory.DisposableBean; public class DisposableBeanImpl implements DisposableBean { // @Override public void destroy() throws Exception { System.out.println("調用接口DisposableBean的destroy方法"); } }
代碼清單:JuiceMaker2_1
import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.BeanNameAware; import org.springframework.beans.factory.InitializingBean; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; public class JuiceMaker2_1 implements BeanNameAware, BeanFactoryAware, ApplicationContextAware, InitializingBean { private String beverageShop = null; private Source source = null; public void init() { System.out.println("【" + this.getClass().getSimpleName() + "】執行自定義初始化方法"); } public void destroy() { System.out.println("【" + this.getClass().getSimpleName() + "】執行自定義銷毀方法"); } public String makeJuice() { String juice = "這是一杯由" + beverageShop + "飲品店,提供的" + source.getSize() + source.getSugar() + source.getFruit(); return juice; } // @Override public void setBeanName(String arg0) { System.out.println("【" + this.getClass().getSimpleName() + "】調用BeanNameAware接口的setBeanName方法"); } // @Override public void setBeanFactory(BeanFactory arg0) throws BeansException { System.out.println("【" + this.getClass().getSimpleName() + "】調用BeanFactoryAware接口的setBeanFactory方法"); } // @Override public void setApplicationContext(ApplicationContext arg0) throws BeansException { System.out.println("【" + this.getClass().getSimpleName() + "】調用ApplicationContextAware接口的setApplicationContext方法"); } // @Override public void afterPropertiesSet() throws Exception { System.out.println("【" + this.getClass().getSimpleName() + "】調用InitializingBean接口的afterPropertiesSet方法"); } /**** setter and getter ****/ }
代碼清單:聲明自定義初始化和銷毀方法的Bean spring-cfg2.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-4.0.xsd"> <!--BeanPostProcessor定義--> <bean id="beanPostProcessor" class="com.ssm.chapter9.bean.BeanPostProcessorImpl"/> <!--DisposableBean定義 --> <bean id="disposableBean" class="com.ssm.chapter9.bean.DisposableBeanImpl"/> <bean id="source" class="com.ssm.chapter9.pojo.Source"> <property name="fruit" value="橙汁"/> <property name="sugar" value="少糖"/> <property name="size" value="3"/> </bean> <bean id="juiceMaker2_1" class="com.ssm.chapter9.pojo.JuiceMaker2_1" init-method="init" destroy-method="destroy"> <property name="beverageShop" value="貢茶"/> <property name="source" ref="source"/> </bean> </beans>
代碼清單:測試Spring Bean的生命周期
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("ssm/chapter9/spring-cfg2.xml"); JuiceMaker2_1 juiceMaker2_1 = (JuiceMaker2_1) ctx.getBean("juiceMaker2_1"); System.out.println(juiceMaker2_1.makeJuice()); ctx.close();
小結
重點在於理解使用Spring IoC的好處和其容器的基本設計,懂得Spring IoC容器主要是為了管理Bean而服務的,需要注意掌握BeanFactory所定義的最為基礎的方法,以及Spring Bean生命周期的用法,通過那些生命周期接口和方法的使用,允許我們自定義初始化和銷毀方法。
參考:SSM框架第九章
