. Spring框架簡介(以下這段話可用於面試求職)
Spring為JavaEE開發提供了一個輕量級的解決方案,主要表現為,
- IOC(或者叫做DI)的核心機制,提供了bean工廠(Spring容器),降低了業務對象替換的復雜性,提高了組件之間的解耦。
- AOP的將一些通用任務,如安全、事務、日志等集中進行管理,提高了復用性和管理的便捷性
- ORM和DAO提供了與第三方持久層框架的良好整合,簡化了底層數據訪問。
- 提供了優秀的Web MVC框架。
可以說Spring是貫穿表現層、業務層、持久層,為javaEE提供一站式解決方案的框架。此外,使用Spring還有如下好處,
- 低侵入設計,代碼污染極低。
- 基於Spring框架的應用,可以獨立於各種應用服務器,實現 write once, run anywhere,
- Spring可以與第三方框架良好整合(如ORM,DAO等模塊與其他框架整合),但同時Spring提供了高度開放性,應用不會被強制依賴Spring,開發者可以自由選擇Spring的部分或者全部。
Spring並不局限於中間層,而是為系統各層都提供了企業級解決方案(例如IOC可以
使用Spring框架可以帶來諸多好處,例如進行數據庫事務處理,遠程調用,JMS消息處理,JMX操作處理,而這些處理都不需要開發人員直接使用相關API(JDBC, JMX, JMS 等)
2.Sping架構
Spring框架是分模塊存在,除了最核心的Spring Core Container(即Spring容器)是必要模塊之外,其他模塊都是可選,視需要而定。
官方文檔Spring4.0的架構圖中,包含了20多個子模塊,大致可以分為四類 1)核心容器(Core Container) 2)數據訪問和集成(Data Access/Integration) 3)Web 4)AOP。
本質上Spring可以總結為以下七個模塊。
其中常用模塊的大致功能如下。
核心容器:核心容器提供 Spring 框架的基本功能。核心容器的主要組件是 BeanFactory
,它是工廠模式的實現。BeanFactory
使用控制反轉 (IOC) 模式將應用程序的配置和依賴性規范與實際的應用程序代碼分開。
Spring 上下文:Spring 上下文是一個配置文件,向 Spring 框架提供上下文信息。Spring 上下文包括企業服務,例如 JNDI、EJB、電子郵件、國際化、校驗和調度功能。
Spring AOP:通過配置管理特性,Spring AOP 模塊直接將面向切面的編程功能集成到了 Spring 框架中。可以將一些通用任務,如安全、事務、日志等集中進行管理,提高了復用性和管理的便捷性。
Spring DAO:為JDBC DAO 抽象層提供了有意義的異常層次結構,可用該結構來管理異常處理和不同數據庫供應商拋出的錯誤消息。異常層次結構簡化了錯誤處理,並且極大地降低了需要編寫的異常代碼數量(例如打開和關閉連接)。Spring DAO 的面向 JDBC 的異常遵從通用的 DAO 異常層次結構。
Spring ORM:Spring 框架插入了若干個 ORM 框架,從而提供了 ORM 的對象關系工具,其中包括 JDO、Hibernate 和 iBatis SQL Map。所有這些都遵從 Spring 的通用事務和 DAO 異常層次結構。
Spring Web 模塊:Web 上下文模塊建立在應用程序上下文模塊之上,為基於 Web 的應用程序提供了上下文。所以,Spring 框架支持與 Jakarta Struts 的集成。Web 模塊還簡化了處理多部分請求以及將請求參數綁定到域對象的工作。
Spring MVC 框架:MVC 框架是一個全功能的構建 Web 應用程序的 MVC 實現。通過策略接口,MVC 框架變成為高度可配置的,MVC 容納了大量視圖技術,其中包括 JSP、Velocity、Tiles、iText 和 POI。
3.環境搭建
首先需要下載Spring框架 spring-framework-4.0.4.RELEASE-dist,4.0.4版官方地址為 http://repo.springsource.org/libs-release-local/org/springframework/spring/4.0.4.RELEASE/ (如果覺得太慢也可以去國內網站下載)
此外,還需要下載一個必要組件 commons-logging-1.1.3-bin ,可以在http://commons.apache.org/官網下載也可以在國內網站下載。
其他諸如log4j之類的並不是必須下載的。
下載好以上兩個壓縮包。在workspace下新建一個lib目錄作為user library。將Spring壓縮包解壓之后,將libs目錄下的 *RELEASE.jar(共21個)都拷貝到你的workspace下的lib目錄;將commons包也解壓,將根目錄的*.1.3.jar(共3個)都拷貝到lib目錄下。
之后在Eclipse中添加一個user library,添加成功后的效果如下,
4.簡單demo及控制反轉(IOC)和依賴注入(DI)簡介
J2EE提倡面向接口編程,Spring也是針對的接口編程,即在代碼中只使用規范(即接口),而將真正的實現類配置在文件中,由Spring的配置文件來決定將會使用哪一個實現類,這也叫做控制反轉(IOC)或者依賴注入(DI)。
現在我們假設有這么一個場景, 我們指定一類人去使用一類斧頭,不同的人可以使用不同的斧頭,當然其效果不一樣。
按照J2EE的建議,首先我們需要定義“人”和“斧頭”兩個規范,即創建兩個接口,
斧頭接口,
1 package spi; 2 3 public interface Axe { 4 public String chop(); 5 }
斧頭接口的一個實現,
1 package spi; 2 3 public class StoneAxe implements Axe { 4 public String chop() { 5 return "石斧砍柴好慢"; 6 } 7 }
人接口
1 package spi; 2 3 public interface Person { 4 public void useAxe(); 5 }
人接口的一個實現,
1 package spi; 2 3 public class Chinese implements Person { 4 private Axe axe; 5 public void setAxe(Axe axe) { 6 this.axe = axe; 7 } 8 public void useAxe() { 9 System.out.println("我打算去砍點柴火"); 10 System.out.println(axe.chop()); 11 } 12 }
下面要寫一個測試類,使用Person接口的一個實現類的對象,去調用Axe的一個實現類的對象,
按照傳統編程方式,我們一般會寫成下面這樣,
1 package spi; 2 3 public class BeanTest { 4 public static void main(String[] args) { 5 Chinese p = new Chinese(); 6 StoneAxe axe = new StoneAxe(); 7 p.setAxe(axe); 8 p.useAxe(); 9 } 10 }
重點是第6行和第7行,即Chinese類和StoneAxe類耦合在了java代碼中,如果現在需求有變,我們在這里要使用一種新的斧頭,即Axe有一個新的實現類SteelAxe,那么就必須修改這里的代碼, SteelAxe axe = new SteelAxe(); 這對於代碼維護其實並不方便。 對於這個問題,Spring的解決方案是將上面的步驟放在配置文件中,具體實現方法是這樣的,
首先創建一個配置文件,名字自定義即可,
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://www.springframework.org/schema/beans 5 http://www.springframework.org/schema/beans/spring-beans.xsd"> 6 <bean id="chinese" class="spi.Chinese"> 7 <property name="axe" ref="stoneAxe" /> 8 </bean> 9 <bean id="stoneAxe" class="spi.StoneAxe" /> 10 <bean id="win" class="javax.swing.JFrame" /> 11 <bean id="date" class="java.util.Date" /> 12 </beans>
可以看到配置文件中定義了上面兩個接口的實現類的具體包路徑,其中stoneAxe還被定義成了Chinese類的一個屬性,
有了這個配置文件之后,Spring就可以在底層利用java反射,首先創建出兩個類對象(Chinese和StoneAxe),接着馬上執行對象的setter方法,依據配置文件中各個類的依賴關系去初始化每個對象的屬性,而這個過程,正是上面傳統編程中的StoneAxe axe = new StoneAxe();p.setAxe(axe);這兩部!
下面看看Spring方式在測試代碼中的寫法,
1 package spi; 2 3 import org.springframework.context.ApplicationContext; 4 import org.springframework.context.support.ClassPathXmlApplicationContext; 5 6 public class BeanTest { 7 public static void main(String[] args) { 8 ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml"); 9 Person p = ctx.getBean("chinese", Person.class); 10 p.useAxe(); 11 } 12 }
執行結果,
1 我打算去砍點柴火 2 石斧砍柴好慢
可以看到,在測試代碼中,完全沒有了Chinese和StoneAxe兩個類的耦合依賴關系,轉而將依賴關系放在了上面的XML文件中,底層通過java反射的方式進行初始化。
即,將java代碼中對象間的依賴關系的控制權交給了Spring配置文件,由Spring來生成對象,並且設置對象間的依賴關系,這就是控制反轉(IOC)或者叫依賴注入(DI)。
Spring自動生成對象(可禁用)和設置依賴關系是最基本的功能。
Spring的IOC(或DI)機制,極大地降低了組件間的耦合,例如對於上面的需求變更,我們只需要在XML文件中新增一個bean節點,並設置好依賴關系即可,而測試代碼不需要任何改變!
新增Axe的實現類,
1 package spi; 2 3 public class SteelAxe implements Axe { 4 public String chop() { 5 return "鋼斧砍柴好快"; 6 } 7 }
修改Spring配置文件,
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://www.springframework.org/schema/beans 5 http://www.springframework.org/schema/beans/spring-beans.xsd"> 6 <bean id="chinese" class="spi.Chinese"> 7 <property name="axe" ref="steelAxe" /> 8 </bean> 9 <bean id="stoneAxe" class="spi.StoneAxe" /> 10 <bean id="steelAxe" class="spi.SteelAxe" /> 11 <bean id="win" class="javax.swing.JFrame" /> 12 <bean id="date" class="java.util.Date" /> 13 </beans>
執行測試類結果,
1 我打算去砍點柴火 2 鋼斧砍柴好快
5.設值注入和構造注入
對於依賴注入,有兩種方式,一種是設置注入,即上面XML配置文件中設置<property />標簽的方式,這種方法本質上是利用反射調用對象的setter方式進行初始化。
另外,還可以使用構造注入的方式,即在XML配置文件中使用<constructor-arg />標簽,不過這種方式要求有對應的構造方法才行。
對於上面的例子,首先我們要讓Chinese類有一個構造方法,
1 public Chinese(Axe axe) { 2 this.axe = axe; 3 }
接着我們將XML配置文件中的<peroperty>標簽用<constructor-arg>標簽替換,
1 <bean id="chinese" class="spi.Chinese"> 2 <!-- <property name="axe" ref="stoneAxe" /> --> 3 <constructor-arg ref="stoneAxe" /> 4 </bean>
我們將得到一樣的結果,只是實現的方式不一樣而已。對於設值注入和構造注入兩種方式如何選擇呢,
一般的,如果對依賴關系無需變化地注入,盡量采用構造注入。其他依賴關系的注入則考慮采用設值方式注入。