Spring框架(一)
Spring:
Spring是一個開源框架,Spring是於2003 年興起的一個輕量級的Java 開發框架,由 Rod Johnson在其著作 Expert One-On-One J2EE Development and Design 中闡述的部分理念和原型衍生而來。它是為了解決企業應用開發的復雜性而創建的。框架的主要優勢之一就是其分層架構,分層架構允許使用者選擇使用哪一個組件,同時為 J2EE 應用程序開發提供集成的框架。Spring 使用基本的 JavaBean來完成以前只可能由 EJB 完成的事情。然而,Spring 的用途不僅限於服務器端的開發。從簡單性、可測試性和松耦合的角度而言,任何 Java 應用都可以從 Spring 中受益。Spring 的核心是控制反轉(IoC)和面向切面(AOP)。簡單來說,Spring 是一個分層的 JavaSE/EEfull-stack( 一站式) 輕量級開源框架。
JavaEE 開發分成三層結構:
* WEB 層:Spring MVC.
* 業務層:Bean 管理:(IOC)
* 持久層:Spring 的 JDBC 模板.ORM 模板用於整合其他的持久層框架.
Spring的優勢:
方便解耦,簡化開發
Spring 就是一個大工廠,可以將所有對象創建和依賴關系維護,交給 Spring 管理
AOP 編程的支持
Spring 提供面向切面編程,可以方便的實現對程序進行權限攔截、運行監控等功能
聲明式事務的支持
只需要通過配置就可以完成對事務的管理,而無需手動編程
方便程序的測試
Spring 對 Junit4 支持,可以通過註解方便的測試 Spring 程序
方便集成各種優秀框架
Spring 不排斥各種優秀的開源框架,其內部提供了對各種優秀框架(如:Struts、Hibernate、MyBatis、Quartz 等)的直接支持
降低 JavaEE API 的使用難度
Spring 對 JavaEE 開發中非常難用的一些 API(JDBC、JavaMail、遠程調用等),都提供了封裝,使這些 API 應用難度大大降低
SpringIOC底層實現原理:
相關概念:
依賴註入和 控制反轉
IOC inversion of control 控制反轉
DI Dependency Injection 依賴註入
IoC是什麽
Ioc—Inversion of Control,即“控制反轉”,不是什麽技術,而是一種設計思想。在Java開發中,Ioc意味著將你設計好的對象交給容器控制,而不是傳統的在你的對象內部直接控制。如何理解好Ioc呢?理解好Ioc的關鍵是要明確“誰控制誰,控制什麽,為何是反轉(有反轉就應該有正轉了),哪些方面反轉了”,那我們來深入分析一下:
●誰控制誰,控制什麽:傳統Java SE程序設計,我們直接在對象內部通過new進行創建對象,是程序主動去創建依賴對象;而IoC是有專門一個容器來創建這些對象,即由Ioc容器來控制對象的創建;誰控制誰?當然是IoC 容器控制了對象;控制什麽?那就是主要控制了外部資源獲取(不只是對象包括比如文件等)。
●為何是反轉,哪些方面反轉了:有反轉就有正轉,傳統應用程序是由我們自己在對象中主動控制去直接獲取依賴對象,也就是正轉;而反轉則是由容器來幫忙創建及註入依賴對象;為何是反轉?因為由容器幫我們查找及註入依賴對象,對象只是被動的接受依賴對象,所以是反轉;哪些方面反轉了?依賴對象的獲取被反轉了。
用圖例說明一下,傳統程序設計如圖,都是主動去創建相關對象然後再組合起來:
傳統應用程序示意圖
當有了IoC/DI的容器後,在客戶端類中不再主動去創建這些對象了
IoC能做什麽
IoC不是一種技術,只是一種思想,一個重要的面向對象編程的法則,它能指導我們如何設計出松耦合、更優良的程序。傳統應用程序都是由我們在類內部主動創建依賴對象,從而導致類與類之間高耦合,難於測試;有了IoC容器後,把創建和查找依賴對象的控制權交給了容器,由容器進行註入組合對象,所以對象與對象之間是松散耦合,這樣也方便測試,利於功能復用,更重要的是使得程序的整個體系結構變得非常靈活。
其實IoC對編程帶來的最大改變不是從代碼上,而是從思想上,發生了“主從換位”的變化。應用程序原本是老大,要獲取什麽資源都是主動出擊,但是在IoC/DI思想中,應用程序就變成被動的了,被動的等待IoC容器來創建並註入它所需要的資源了。
IoC很好的體現了面向對象設計法則之一—— 好萊塢法則:“別找我們,我們找你”;即由IoC容器幫對象找相應的依賴對象並註入,而不是由對象主動去找。
IoC和DI
DI—Dependency Injection,即“依賴註入”:是組件之間依賴關系由容器在運行期決定,形象的說,即由容器動態的將某個依賴關系註入到組件之中。依賴註入的目的並非為軟件系統帶來更多功能,而是為了提升組件重用的頻率,並為系統搭建一個靈活、可擴展的平臺。通過依賴註入機制,我們只需要通過簡單的配置,而無需任何代碼就可指定目標需要的資源,完成自身的業務邏輯,而不需要關心具體的資源來自何處,由誰實現。
理解DI的關鍵是:“誰依賴誰,為什麽需要依賴,誰註入誰,註入了什麽”,那我們來深入分析一下:
●誰依賴於誰:當然是應用程序依賴於IoC容器;
●為什麽需要依賴:應用程序需要IoC容器來提供對象需要的外部資源;
●誰註入誰:很明顯是IoC容器註入應用程序某個對象,應用程序依賴的對象;
●註入了什麽:就是註入某個對象所需要的外部資源(包括對象、資源、常量數據)。
IoC和DI由什麽關系呢?其實它們是同一個概念的不同角度描述,由於控制反轉概念比較含糊(可能只是理解為容器控制對象這一個層面,很難讓人想到誰來維護對象關系),所以2004年大師級人物Martin Fowler又給出了一個新的名字:“依賴註入”,相對IoC 而言,“依賴註入”明確描述了“被註入對象依賴IoC容器配置依賴對象”。
面向對象五大原則:
單一職責原則(SRP)
開放封閉原則(OCP)
裏氏替換原則(LSP)
依賴倒置原則(DIP)
接口隔離原則(ISP)
單一職責原則(SRP)
• 一個類應該僅有一個引起它變化的原因(最簡單,最容易理解卻最不容易做到的一個設計原則)
職員類例子:
比如在職員類裏,將工程師、銷售人員、銷售經理這些情況都放在職員類裏考慮,其結果將會非常混亂,在這個假設下,職員類裏的每個方法都要if else判斷是哪種情況,從類結構上來說將會十分臃腫,並且上述三種的職員類型,不論哪一種發生需求變化,都會改變職員類!這個是大家所不願意看到的!
開放封閉原則(OCP)
• 既開放又封閉,對擴展是開放的,對更改是封閉的!
• 擴展即擴展現行的模塊,當我們軟件的實際應用發生改變時,出現新的需求,就需要我們對模塊進行擴展,使其能夠滿足新的需求!
更改封閉即是在我們對模塊進行擴展時,勿需對源有程序代碼和DLL進行修改或重新編譯文件!
這個原則對我們在設計類的時候很有幫助,堅持這個原則就必須盡量考慮接口封裝,抽象機制和多態技術!
裏氏替換原則(LSP)
• 子類可以替換父類並且出現在父類能夠出現的任何地方
• 這個原則也是在貫徹GOF倡導的面向接口編程!
在這個原則中父類應盡可能使用接口或者抽象類來實現!
子類通過實現了父類接口,能夠替父類的使用地方!
通過這個原則,我們客戶端在使用父類接口的時候,通過子類實現!
意思就是說我們依賴父類接口,在客戶端聲明一個父類接口,通過其子類來實現
這個時候就要求子類必須能夠替換父類所出現的任何地方,這樣做的好處就是,在根據新要求擴展父類接口的新子類的時候而不影響當前客戶端的使用!
依賴倒置原則(DIP)
• 傳統的結構化編程中,最上層的模塊通常都要依賴下面的子模塊來實現,也
稱為高層依賴低層!
所以DIP原則就是要逆轉這種依賴關系,讓高層模塊不要依賴低層模塊,所以稱之為依賴倒置原則!
ISP 接口隔離原則
• 這個原則的意思是:使用多個專門的接口比使用單個接口要好的多!
這個我有體會,在我實際編程中,為了減少接口的定義,將許多類似的方法都放在一個接口中,最後發現,維護和實現接口的時候花了太多精力,而接口所定義的操作相當於對客戶端的一種承諾,這種承諾當然是越少越好,越精練越好,過多的承諾帶來的就是你的大量精力和時間去維護!
反射機制:
1, 通過spring來獲取一個對象的實例
2, 通過spring進行屬性註入
setter方法註入
構造器註入
接口註入
p標記的使用
<bean p:username=""></bean>
3, 將一個對象註入到另一個對象<ref bean="...">
4, AutoWired(byType, byName)
5, scope, lazy-init, init-method, destroy-method(相當的不重要)
scope="singleton(單例) / prototype(原型)"
lazy-init="true" // 延遲加載
___init-method="" destory-method=""(不要和prototype一起使用)
autowire
例子:
下載並引入相關jar包:
結構:
配置相關文件:
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 http://www.springframework.org/schema/beans/spring-beans.xsd"> 5 6 <bean id="user" class="com.model.User"> 7 <!-- 通過Spring給類註入屬性,通過空參構造方法 --> 8 <property name="username"> 9 <value>hanqi</value> 10 </property> 11 <property name="password"> 12 <value>123</value> 13 </property> 14 15 <!-- 16 另一種通過帶參構造方法 17 <constructor-arg index="0" value="name1"></constructor-arg> 18 <constructor-arg index="1" value="pwd1"></constructor-arg> 19 --> 20 </bean> 21 22 </beans>
model包:
1 package com.model; 2 3 public class User { 4 private String username; 5 private String password; 6 7 8 9 public User() { 10 super(); 11 System.out.println("調用User類的空參構造方法"); 12 // TODO Auto-generated constructor stub 13 } 14 public User(String username, String password) { 15 super(); 16 this.username = username; 17 this.password = password; 18 System.out.println("調用User類的帶參構造方法 "); 19 } 20 public String getUsername() { 21 return username; 22 } 23 public void setUsername(String username) { 24 this.username = username; 25 } 26 public String getPassword() { 27 return password; 28 } 29 public void setPassword(String password) { 30 this.password = password; 31 } 32 @Override 33 public String toString() { 34 return "User [username=" + username + ", password=" + password + "]"; 35 } 36 37 38 39 }
測試1:
1 package com.test; 2 3 import org.springframework.context.ApplicationContext; 4 import org.springframework.context.support.ClassPathXmlApplicationContext; 5 6 import com.model.User; 7 8 public class Test { 9 public static void main(String[] args) { 10 ApplicationContext ac=new ClassPathXmlApplicationContext("Spring-all.xml");//調用此方法時類已經實例化好了 11 User u=(User)ac.getBean("user");//拿到實例化的類,帶有默認的值 12 13 System.out.println(u); 14 ((ClassPathXmlApplicationContext)ac).close(); 15 16 } 17 }
測試2:
1 package com.test; 2 3 import org.springframework.context.ApplicationContext; 4 import org.springframework.context.support.ClassPathXmlApplicationContext; 5 6 import com.model.User; 7 8 public class Test { 9 public static void main(String[] args) { 10 ApplicationContext ac=new ClassPathXmlApplicationContext("Spring-all.xml");//調用此方法時類已經實例化好了 11 12 User u=(User)ac.getBean("user");//拿到實例化的類 13 14 u.setUsername("u"); 15 u.setPassword("p"); 16 System.out.println(u); 17 ((ClassPathXmlApplicationContext)ac).close(); 18 19 } 20 }
測試3:
1 package com.test; 2 3 import java.lang.reflect.Method; 4 5 import com.model.User; 6 7 public class Test2 { 8 public static void main(String[] args) { 9 try { 10 //實例化一個類,<?>代表可以是任何類型 11 Class<?> cla=Class.forName("com.model.User"); 12 //cla.getConstructor(parameterTypes);獲取類裏的構造方法 13 //cla.getFields();//獲取類裏的成員變量 14 15 //獲得對象實例 16 User u=(User)cla.newInstance(); 17 //u.setUsername("直接調用set設置的"); 18 19 //獲取類裏的所有方法 20 Method[] me=cla.getMethods(); 21 22 Object obj=null; 23 Object obj1=null; 24 25 for(Method m:me){ 26 //找到方法,回調方法反射 27 if("setUsername".equals(m.getName())){ 28 obj=m.invoke(u, "回調反射"); 29 } 30 } 31 for(Method m:me){ 32 if("getUsername".equals(m.getName())){ 33 obj1=m.invoke(u); 34 } 35 } 36 //set方法沒有返回值,打印null 37 System.out.println("setUsername方法的返回值:"+obj); 38 //直接打印對象,屬性null 39 System.out.println("對象:"+u); 40 // 41 System.out.println("getUsername方法的返回值:"+obj1); 42 43 } catch (Exception e) { 44 // TODO Auto-generated catch block 45 e.printStackTrace(); 46 } 47 } 48 }
Spring框架(一)