spring MVC在性能上是要比struts2要好的。struts2的性能低的緣由是由於OGNL和值堆形成的,在springMVC中,若是併發性比較高,能夠用freemaker進行顯示,而不是用OGNL和值棧,這樣性能上會有很大的提升。前端
springMVC運行流程圖(在網上找的)java
這個圖化的很好,比官方文檔的畫的好多了web
這裏須要瞭解一個dispatcherServlet的初始化spring
1.把初始化的那些init-param讀到Servlet的屬性裏。咱們知道Servlet的init-param是放在ServletConfig裏的,咱們能夠用循環去取這些屬性。可是每次都這麼幹實在太累了,幹嘛不把在Servlet裏增長几個property,再這些init-param直放到Servlet的property裏呢?呵呵,之後那些初始參數均可以直接拿來用啦,真方便。DispatchServlet的一個祖先類叫作HttpServletBean就是專門幹這個的。之後假如咱們要寫本身的Servlet也能夠直接繼承HttpServletBean這個類,這樣讀ServletConfig的操做都省掉了,哈哈!json
2.從ServletContext裏取出ApplicationContext,並擴展成本身的ApplicationContext.spring-mvc
在Spring MVC裏,咱們卻能夠有好多個Servlet!它們能夠處理不一樣類型的request,並且更重要的是它們的ApplicationContext不是相同的,它們共享了一個父ApplicationContext,也就是從ServletContext裏取出來的那個,可是它們卻會根據本身的配置做擴展,造成這個Servlet特有的ApplicationContext。這個子的ApplicationContext裏有本身的namespace,也就是將一個叫作(假如servlet名稱叫xiecc) xiecc-servlet.xml的配置文件讀進來,行成一個本身的ServletContext。因此這些過程全是在DispatchSevlet的一個父類FrameworkServlet裏乾的服務器
3.初始化dispatcherServlet的接口,將applicationcontext定義好的接口注入dispatcherServlet中併發
initMultipartResolver();mvc
initLocaleResolver();app
initThemeResolver();
initHandlerMappings();
initHandlerAdapters();
initHandlerExceptionResolvers();
initViewResolvers();
dispatcherServlet是不負責具體的操做的,他將具體的操做都委託給相應的接口,這是Template Method的Strategy模式
1. 用戶向服務器發送請求,請求被Spring 前端控制Servelt DispatcherServlet捕獲;
這裏在web.xml中配置dispatcherServlet,文檔解釋dispatcherServlet Central dispatcher for HTTP request handlers/controllers,Dispatches to registered handlers for processing a web request, providing convenient mapping and exception handling facilities意思基本是處理request請求並註冊handlers
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <servlet> <servlet-name>dispatcherServlet</servlet-name> <servlet-class> org.springframework.web.servlet.DispatcherServlet </servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/hib-config.xml,/WEB-INF/springmvc-servlet.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>dispatcherServlet</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping> </web-app>
2.DispatcherServlet對請求URL進行解析。DispatcherServlet裏面的BeanNameUrlHandlerMapping這個類實現了HandlerMapping這個接口。用來實現映射(The mapping is from URL to bean name)。BeanNameUrlHandlerMapping 的解釋
Implementation of the org.springframework.web.servlet.HandlerMapping
interface that map from URLs to beans with names that start with a slash ("/"), similar to how Struts maps URLs to action names.
用的多的仍是handlerMapping的SimpleUrlHandlerMapping,
這是dispatcherServlet中定義的handlerMapping的集合
/** List of HandlerMappings used by this servlet */ private List<HandlerMapping> handlerMappings;
這裏我請求的url
http://oulin:8080/springMVC/user.do?uname=123&method=reg3
requestUrl字符串一截,拿到"/user.do"再去handlerMappings裏去找對應的"/user.do",將對應的controller和一組interceptor組裝成handlerExecutionChain。
<mvc:interceptors>中拿到一組interceptor
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd"> <!-- 對web包中的全部類進行掃描,以完成Bean建立和自動依賴注入的功能 --> <context:component-scan base-package="com.sxt.web" /> <mvc:annotation-driven /> <!-- 支持spring3.0新的mvc註解 --> <!-- 啓動Spring MVC的註解功能,完成請求和註解POJO的映射 --> <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"> <property name="cacheSeconds" value="0" /> <property name="messageConverters"> <list> <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"></bean> </list> </property> </bean> <mvc:interceptors> <bean class="com.sxt.interceptor.MyInterceptor"></bean> <!-- 攔截全部springmvc的url! --> <mvc:interceptor> <mvc:mapping path="/user.do" /> <!--<mvc:mapping path="/test/*" />--> <bean class="com.sxt.interceptor.MyInterceptor2"></bean> </mvc:interceptor> </mvc:interceptors> <!--對模型視圖名稱的解析,即在模型視圖名稱添加先後綴 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" p:suffix=".jsp"> <!-- 若是使用jstl的話,配置下面的屬性 --> <property name="viewClass" value="org.springframework.web.servlet.view.JstlView" /> </bean> <!-- 處理文件上傳 --> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <property name="defaultEncoding" value="gbk" /> <!-- 默認編碼 (ISO-8859-1) --> <property name="maxInMemorySize" value="10240" /> <!-- 最大內存大小 (10240)--> <property name="uploadTempDir" value="/upload/" /> <!-- 上傳後的目錄名 (WebUtils#TEMP_DIR_CONTEXT_ATTRIBUTE) --> <property name="maxUploadSize" value="-1" /> <!-- 最大文件大小,-1爲無限止(-1) --> </bean> </beans>
userController.java
package com.sxt.action; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.SessionAttributes; import org.springframework.web.servlet.ModelAndView; import com.sxt.po.User; import com.sxt.service.UserService; @Controller @RequestMapping("/user.do") @SessionAttributes({"u","a"}) public class UserController { @Resource private UserService userService; @RequestMapping(params="method=reg") public String reg(String uname){ System.out.println("UserController.reg()"); System.out.println(uname); userService.add(uname); return "index"; } @RequestMapping(params="method=reg2") public ModelAndView reg2(User user){ System.out.println("UserController.reg2()"); System.out.println(user.getUname()); ModelAndView mav = new ModelAndView("index"); return mav; } @RequestMapping(params="method=reg3") public String reg3(@RequestParam("uname") String name,HttpServletRequest req,ModelMap map){ System.out.println("UserController.reg()"); System.out.println(name); req.getSession().setAttribute("c", "ccc"); map.put("a", "aaa"); return "index"; } @RequestMapping(params="method=reg4") public String reg4(@ModelAttribute("a") String a,HttpServletRequest req,ModelMap map){ System.out.println("UserController.reg4()"); System.out.println(a); return "redirect:http://www.baidu.com"; } @RequestMapping(params="method=reg5") public ModelAndView reg5(String uname){ System.out.println("UserController.reg5()"); ModelAndView mav = new ModelAndView(); mav.setViewName("index"); User u = new User("123"); User u2 = new User("1234"); mav.addObject(u); mav.addObject("uu", u2); return mav; } public UserService getUserService() { return userService; } public void setUserService(UserService userService) { this.userService = userService; } }
3. DispatcherServlet 根據得到的Handler,選擇一個合適的HandlerAdapter。(附註:若是成功得到HandlerAdapter後,此時將開始執行攔截器的preHandler(...)方法)
我前面說了HandlerExecutionChain就是一個Controller和一組interceptors。這是咱們執行一個request最基本的單元啦。
不過現實狀況會稍有些出入,HandlerExecutionChain實際上包括的一個Object和一組interceptor。這個Object是Adaptor,它能夠是Controller的Adaptor,也能夠是其它類的Adaptor。但現實中咱們通常用到的都是Controller,所以不詳細分析啦,這裏用了Adaptor後大大下降了代碼的可讀性,來換取與Controller非緊耦合的靈活性。至少我如今認爲這樣作不是太值。