一、SpringMVC的工做原理前端
SpringMVC框架介紹
- Spring MVC屬於SpringFrameWork的後續產品,已經融合在Spring Web Flow裏面。
spring 框架提供了構建 Web 應用程序的全功能 MVC 模塊。使用 Spring 可插入的 MVC 架構,能夠選擇是使用內置的 Spring Web 框架仍是 Struts 這樣的 Web 框架。經過策略接口,Spring 框架是高度可配置的,並且包含多種視圖技術,例如 JavaServer Pages(JSP)技術、Velocity、Tiles、iText 和 POI。Spring MVC 框架並不知道使用的視圖,因此不會強迫您只使用 JSP 技術。java
Spring MVC 分離了控制器、模型對象、分派器以及處理程序對象的角色,這種分離讓它們更容易進行定製。程序員
- Spring的MVC框架主要由DispatcherServlet、處理器映射、處理器(控制器)、視圖解析器、視圖組成。
SpringMVC原理圖
![](http://static.javashuo.com/static/loading.gif)
SpringMVC接口解釋
Spring提供的前端控制器,全部的請求都有通過它來統一分發。在DispatcherServlet將請求分發給Spring Controller以前,須要藉助於Spring提供的HandlerMapping定位到具體的Controller。spring
可以完成客戶請求到Controller映射。編程
須要爲併發用戶處理上述請求,所以實現Controller接口時,必須保證線程安全而且可重用。安全
Controller將處理用戶請求,這和Struts Action扮演的角色是一致的。一旦Controller處理完用戶請求,則返回ModelAndView對象給DispatcherServlet前端控制器,ModelAndView中包含了模型(Model)和視圖(View)。架構
從宏觀角度考慮,DispatcherServlet是整個Web應用的控制器;從微觀考慮,Controller是單個Http請求處理過程當中的控制器,而ModelAndView是Http請求過程當中返回的模型(Model)和視圖(View)。併發
Spring提供的視圖解析器(ViewResolver)在Web應用中查找View對象,從而將相應結果渲染給客戶。app
SpringMVC運行原理
- 客戶端請求提交到DispatcherServlet
- 由DispatcherServlet控制器查詢一個或多個HandlerMapping,找處處理請求的Controller
- DispatcherServlet將請求提交到Controller
- Controller調用業務邏輯處理後,返回ModelAndView
- DispatcherServlet查詢一個或多個ViewResoler視圖解析器,找到ModelAndView指定的視圖
- 視圖負責將結果顯示到客戶端
- DispatcherServlet是整個Spring MVC的核心。它負責接收HTTP請求組織協調Spring MVC的各個組成部分。其主要工做有如下三項:
- 截獲符合特定格式的URL請求。
- 初始化DispatcherServlet上下文對應的WebApplicationContext,並將其與業務層、持久化層的WebApplicationContext創建關聯。
- 初始化Spring MVC的各個組成組件,並裝配到DispatcherServlet中。
-
面向切面變成理解:
面向切面編程(AOP是Aspect Oriented Program的首字母縮寫) ,咱們知道,面向對象的特色是繼承、多態和封裝。而封裝就要求將功能分散到不一樣的對象中去,這在軟件設計中每每稱爲職責分配。實際上也就是說,讓不一樣的類設計不一樣的方法。這樣代碼就分散到一個個的類中去了。這樣作的好處是下降了代碼的複雜程度,使類可重用。
可是人們也發現,在分散代碼的同時,也增長了代碼的重複性。什麼意思呢?好比說,咱們在兩個類中,可能都須要在每一個方法中作日誌。按面向對象的設計方法,咱們就必須在兩個類的方法中都加入日誌的內容。也許他們是徹底相同的,但就是由於面向對象的設計讓類與類之間沒法聯繫,而不能將這些重複的代碼統一塊兒來。
也許有人會說,那好辦啊,咱們能夠將這段代碼寫在一個獨立的類獨立的方法裏,而後再在這兩個類中調用。可是,這樣一來,這兩個類跟咱們上面提到的獨立的類就有耦合了,它的改變會影響這兩個類。那麼,有沒有什麼辦法,能讓咱們在須要的時候,隨意地加入代碼呢?
這種在運行時,動態地將代碼切入到類的指定方法、指定位置上的編程思想就是面向切面的編程。
通常而言,咱們管切入到指定類指定方法的代碼片斷稱爲切面,而切入到哪些類、哪些方法則叫切入點。有了AOP,咱們就能夠把幾個類共有的代碼,抽取到一個切片中,等到須要時再切入對象中去,從而改變其原有的行爲。
這樣看來,AOP其實只是OOP的補充而已。OOP從橫向上區分出一個個的類來,而AOP則從縱向上向對象中加入特定的代碼。有了AOP,OOP變得立體了。若是加上時間維度,AOP使OOP由原來的二維變爲三維了,由平面變成立體了。從技術上來講,AOP基本上是經過代理機制實現的。
AOP在編程歷史上能夠說是里程碑式的,對OOP編程是一種十分有益的補充。
二、spring 四種注入方式框架
日常的java開發中,程序員在某個類中須要依賴其它類的方法,則一般是new一個依賴類再調用類實例的方法,這種開發存在的問題是new的類實例很差統一管理,spring提出了依賴注入的思想,即依賴類不禁程序員實例化,而是經過spring容器幫咱們new指定實例而且將實例注入到須要該對象的類中。依賴注入的另外一種說法是「控制反轉」,通俗的理解是:日常咱們new一個實例,這個實例的控制權是咱們程序員,而控制反轉是指new實例工做不禁咱們程序員來作而是交給spring容器來作。
spring有多種依賴注入的形式,下面僅介紹spring經過xml進行IOC配置的方式:
這是最簡單的注入方式,假設有一個SpringAction,類中須要實例化一個SpringDao對象,那麼就能夠定義一個private的SpringDao成員變量,而後建立SpringDao的set方法(這是ioc的注入入口):
- package com.bless.springdemo.action;
- public class SpringAction {
-
- private SpringDao springDao;
-
- public void setSpringDao(SpringDao springDao) {
- this.springDao = springDao;
- }
-
- public void ok(){
- springDao.ok();
- }
- }
隨後編寫spring的xml文件,<bean>中的name屬性是class屬性的一個別名,class屬性指類的全名,由於在SpringAction中有一個公共屬性Springdao,因此要在<bean>標籤中建立一個<property>標籤指定SpringDao。<property>標籤中的name就是SpringAction類中的SpringDao屬性名,ref指下面<bean name="springDao"...>,這樣實際上是spring將SpringDaoImpl對象實例化而且調用SpringAction的setSpringDao方法將SpringDao注入:
- <!--配置bean,配置後該類由spring管理-->
- <bean name="springAction" class="com.bless.springdemo.action.SpringAction">
- <!--(1)依賴注入,配置當前類中相應的屬性-->
- <property name="springDao" ref="springDao"></property>
- </bean>
- <bean name="springDao" class="com.bless.springdemo.dao.impl.SpringDaoImpl"></bean>
這種方式的注入是指帶有參數的構造函數注入,看下面的例子,我建立了兩個成員變量SpringDao和User,可是並未設置對象的set方法,因此就不能支持第一種注入方式,這裏的注入方式是在SpringAction的構造函數中注入,也就是說在建立SpringAction對象時要將SpringDao和User兩個參數值傳進來:
- public class SpringAction {
-
- private SpringDao springDao;
- private User user;
-
- public SpringAction(SpringDao springDao,User user){
- this.springDao = springDao;
- this.user = user;
- System.out.println("構造方法調用springDao和user");
- }
-
- public void save(){
- user.setName("卡卡");
- springDao.save(user);
- }
- }
在XML文件中一樣不用<property>的形式,而是使用<constructor-arg>標籤,ref屬性一樣指向其它<bean>標籤的name屬性:
- <bean name="springAction" class="com.bless.springdemo.action.SpringAction">
-
- <constructor-arg ref="springDao"></constructor-arg>
- <constructor-arg ref="user"></constructor-arg>
- </bean>
- <bean name="springDao" class="com.bless.springdemo.dao.impl.SpringDaoImpl"></bean>
- <bean name="user" class="com.bless.springdemo.vo.User"></bean>
解決構造方法參數的不肯定性,你可能會遇到構造方法傳入的兩參數都是同類型的,爲了分清哪一個該賦對應值,則須要進行一些小處理:
下面是設置index,就是參數位置:
- <bean name="springAction" class="com.bless.springdemo.action.SpringAction">
- <constructor-arg index="0" ref="springDao"></constructor-arg>
- <constructor-arg index="1" ref="user"></constructor-arg>
- </bean>
另外一種是設置參數類型:
- <constructor-arg type="java.lang.String" ref=""/>
靜態工廠顧名思義,就是經過調用靜態工廠的方法來獲取本身須要的對象,爲了讓spring管理全部對象,咱們不能直接經過"工程類.靜態方法()"來獲取對象,而是依然經過spring注入的形式獲取:
- package com.bless.springdemo.factory;
-
- import com.bless.springdemo.dao.FactoryDao;
- import com.bless.springdemo.dao.impl.FactoryDaoImpl;
- import com.bless.springdemo.dao.impl.StaticFacotryDaoImpl;
-
- public class DaoFactory {
-
- public static final FactoryDao getStaticFactoryDaoImpl(){
- return new StaticFacotryDaoImpl();
- }
- }
一樣看關鍵類,這裏我須要注入一個FactoryDao對象,這裏看起來跟第一種注入如出一轍,可是看隨後的xml會發現有很大差異:
- public class SpringAction {
-
- private FactoryDao staticFactoryDao;
-
- public void staticFactoryOk(){
- staticFactoryDao.saveFactory();
- }
-
- public void setStaticFactoryDao(FactoryDao staticFactoryDao) {
- this.staticFactoryDao = staticFactoryDao;
- }
- }
Spring的IOC配置文件,注意看<bean name="staticFactoryDao">指向的class並非FactoryDao的實現類,而是指向靜態工廠DaoFactory,而且配置 factory-method="getStaticFactoryDaoImpl"指定調用哪一個工廠方法:
- <bean name="springAction" class="com.bless.springdemo.action.SpringAction" >
-
- <property name="staticFactoryDao" ref="staticFactoryDao"></property>
- </property>
- </bean>
-
- <bean name="staticFactoryDao" class="com.bless.springdemo.factory.DaoFactory" factory-method="getStaticFactoryDaoImpl"></bean>
-
實例工廠的意思是獲取對象實例的方法不是靜態的,因此你須要首先new工廠類,再調用普通的實例方法:
- public class DaoFactory {
-
- public FactoryDao getFactoryDaoImpl(){
- return new FactoryDaoImpl();
- }
- }
那麼下面這個類沒什麼說的,跟前面也很類似,可是咱們須要經過實例工廠類建立FactoryDao對象:
- public class SpringAction {
-
- private FactoryDao factoryDao;
-
- public void factoryOk(){
- factoryDao.saveFactory();
- }
-
- public void setFactoryDao(FactoryDao factoryDao) {
- this.factoryDao = factoryDao;
- }
- }
最後看spring配置文件:
- <bean name="springAction" class="com.bless.springdemo.action.SpringAction">
-
- <property name="factoryDao" ref="factoryDao"></property>
- </bean>
-
-
- <bean name="daoFactory" class="com.bless.springdemo.factory.DaoFactory"></bean>
- <bean name="factoryDao" factory-bean="daoFactory" factory-method="getFactoryDaoImpl"></bean>
Spring IOC注入方式用得最多的是(1)(2)種,多謝多練就會很是熟練。
另外注意:經過Spring建立的對象默認是單例的,若是須要建立多實例對象能夠在<bean>標籤後面添加一個屬性:
- <bean name="..." class="..." scope="prototype">