spring MVC在性能上是要比struts2要好的。struts2的性能低的原因是因为OGNL和值堆造成的,在springMVC中,如果并发性比较高,可以用freemaker进行显示,而不是用OGNL和值栈,这样性能上会有很大的提高。
springMVC运行流程图(在网上找的)
这个图化的很好,比官方文档的画的好多了
这里需要了解一个dispatcherServlet的初始化
1.把初始化的那些init-param读到Servlet的属性里。我们知道Servlet的init-param是放在ServletConfig里的,我们可以用循环去取这些属性。但是每次都这么干实在太累了,干吗不把在Servlet里增加几个property,再这些init-param直放到Servlet的property里呢?呵呵,以后那些初始参数都可以直接拿来用啦,真方便。DispatchServlet的一个祖先类叫做HttpServletBean就是专门干这个的。以后假如我们要写自己的Servlet也可以直接继承HttpServletBean这个类,这样读ServletConfig的操作都省掉了,哈哈!
2.从ServletContext里取出ApplicationContext,并扩展成自己的ApplicationContext.
在Spring MVC里,我们却可以有好多个Servlet!它们可以处理不同类型的request,而且更重要的是它们的ApplicationContext不是相同的,它们共享了一个父ApplicationContext,也就是从ServletContext里取出来的那个,但是它们却会根据自己的配置作扩展,形成这个Servlet特有的ApplicationContext。这个子的ApplicationContext里有自己的namespace,也就是将一个叫做(假如servlet名称叫xiecc) xiecc-servlet.xml的配置文件读进来,行成一个自己的ServletContext。所以这些过程全是在DispatchSevlet的一个父类FrameworkServlet里干的
3.初始化dispatcherServlet的接口,将applicationcontext定义好的接口注入dispatcherServlet中
initMultipartResolver();
initLocaleResolver();
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非紧耦合的灵活性。至少我现在认为这样做不是太值。