【WEB】初探Spring MVC框架

Spring MVC框架算是当下比较流行的Java开源框架。但实话实说,做了几年WEB项目,完全没有SpringMVC实战经验,乃至在某些交流场合下被同行严重鄙视“奥特曼”了。“心塞”的同时,只好默默的打开IDE从HelloWorld开始。

初步认识

宏观视野决定微观实现的质量,首先对Spring MVC框架组件及其流程做一个简单的认识。以下是从互联网中某Spring MVC教材扣来一张介绍图(懒得重复造轮子了):

从上图可以看出,Spring MVC框架的核心组件有DispatcherServlet、HandlerMapping、HandlerAdapter、Handler、ModelAndView、Model、View以及ViewResolver。既然是核心组件,怎么也得结合组件源码来探索个究竟吧:

DispatcherServlet

 

从名字可以看出,这就是一个Servlet实例,既然是Servlet,那当然是Srping MVC框架入口了,也是web.xml的一个Spring MVC配置项:

<servlet>
    <servlet-name>springmvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:springmvc-servlet.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup></servlet>
<servlet-mapping>
    <servlet-name>springmvc</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

其中springmvc为servlet的自定义命名名称,其中Spring MVC配置文件也是默认名称为[servletName]-servlet.xml。

从DispatcherServlet源码看到到,DispatcherServlet的基础结构是:

DispatcherServlet extend FrameworkServlet

FrameworkServlet extend HttpServletBean

HttpServletBean extend HttpServlet

初略的看了一下DispatcherServlet的干系源码,主要做了两大部分,其一是初始化WEB容器的上下文信息和一些Spring MVC策略容器(如HandlerMapping、HandlerAdapter等),在启动WEB容器时可以通过控制台输出看到Spring MVC的一些初始化操作:

……
信息: Starting Servlet Engine: Apache Tomcat/6.0.13
2016-4-12 10:51:54 org.apache.catalina.core.ApplicationContext log
信息: Initializing Spring FrameworkServlet ‘springmvc‘
2016-4-12 10:51:54 org.springframework.web.servlet.FrameworkServlet initServletBean
信息: FrameworkServlet ‘springmvc‘: initialization started
2016-4-12 10:51:54 org.springframework.context.support.AbstractApplicationContext prepareRefresh
信息: Refreshing WebApplicationContext for namespace ‘springmvc-servlet‘: startup date [Tue Apr 12 10:51:54 CST 2016]; root of context hierarchy
2016-4-12 10:51:54 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [springmvc-servlet.xml]
2016-4-12 10:51:55 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
信息: Pre-instantiating singletons in org.s[email protected]c7f06: defining beans [helloWorldAnnotation,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping#0,org.springframework.format.support.FormattingConversionServiceFactoryBean#0,org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter#0,org.springframework.web.servlet.handler.MappedInterceptor#0,org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping#0,org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter#0,org.springframework.web.servlet.view.InternalResourceViewResolver#0,/helloWorldController]; root of factory hierarchy
2016-4-12 10:51:55 org.springframework.web.servlet.handler.AbstractUrlHandlerMapping registerHandler
信息: Mapped URL path [/helloWorldAnnotation] onto handler [[email protected]]
2016-4-12 10:51:55 org.springframework.web.servlet.handler.AbstractUrlHandlerMapping registerHandler
信息: Mapped URL path [/helloWorldAnnotation.*] onto handler [[email protected]]
2016-4-12 10:51:55 org.springframework.web.servlet.handler.AbstractUrlHandlerMapping registerHandler
信息: Mapped URL path [/helloWorldAnnotation/] onto handler [[email protected]]
2016-4-12 10:51:55 org.springframework.web.servlet.handler.AbstractUrlHandlerMapping registerHandler
信息: Mapped URL path [/helloWorldController] onto handler [[email protected]]
2016-4-12 10:51:55 org.springframework.web.servlet.FrameworkServlet initServletBean
信息: FrameworkServlet ‘springmvc‘: initialization completed in 1222 ms
……

其二就是对MVC容器的流程控制,其主要流程控制方法是doDispatch,接下来结合源码针对此方法的一些重要操作进行分析和学习:

//检查请求是否是multipart(如文件上传),如果是则通过MultipartResolver解析
processedRequest = checkMultipart(request);
multipartRequestParsed = processedRequest != request;

//获取请求对应的mappedHandler
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}

//获取请求对应的HandlerAdapter
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

//由适配器执行处理器(调用处理器相应功能处理方法)
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

//如果HandlerAdapter没有对应的ModelAndView响应,怎通过上下文获取默认对应的view,接着
applyDefaultViewName(request, mv);

//看applyPostHandle得知,这是定义拦截器的处理方法
mappedHandler.applyPostHandle(processedRequest, response, mv);

//解析视图并进行视图的渲染
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);

从doDispatch方法流程分析可以看出,跟以上Spring MVC框架流程图的处理流程是一致的,整个DispatcherServlet组件就是Spring MVC的总流程控制器,再形象一点就如下图所示:

HandlerMapping

察人先察色,HandlerMapping中文意思就是“处理映射”,作为一个强大的开源框架,命名自然不会乱来,通过名称就大概知其所以。看看getHandle这个方法:

protected HandlerExecutionChain getHandler(HttpServletRequest request)…

先不看源码,就大概可以猜个一二,这是通过request参数,获取一个对应的的处理类,而这个HandlerExecutionChain就是这个返回的处理类。这个HandlerMapping已经在项目启动的时候跟随Servlet一同初始化了:

initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context);
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);

而getHandler方法可以通过request获取请求的所有信息,包括请求方法、URL路径等,就可以通过这个映射容器找出对应的处理类了。下面再看看这个HandlerExecutionChain响应类属性:

private final Object handler;
private HandlerInterceptor[] interceptors;
private List<HandlerInterceptor> interceptorList;
private int interceptorIndex = -1;

它包括了请求处理的所有拦截实例和核心处理handler实例,这都会在DispatcherServlet往下几个步骤会使用到的,具体可以往上回看DispatcherServlet的处理流程。

HandlerAdapter

还是从名称理解开始,HandlerAdapter中文意思就是处理对象适配器,按意思就是说Spring MVC有很多个Handler处理对象,这个处理器实际就是一个Handler代理。那么如果不自己定义Handler代理的话,那默认有多少个呢,那就可以看看DispatcherServlet.properties这个配置文件了:

Name:org.springframework.web.servlet.HandlerAdapter
Value:org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter

哦,原来默认有HttpRequestHandlerAdapter、SimpleControllerHandlerAdapter和AnnotationMethodHandlerAdapter一共三个默认的Handler代理。那他们分别有什么用呢,看看我自己亲自动手做过Spring MVC HelloWorld实例就很明白了,我通过两种方式实现了两个HelloWorld Handler,一个在配置文件配置的bean:

<bean name="/helloWorldController" class="com.maventest.springmvc.HelloWorldController"/>
public class HelloWorldController implements Controller{

    public ModelAndView handleRequest(HttpServletRequest arg0,
            HttpServletResponse arg1) throws Exception {

        ModelAndView mv = new ModelAndView();
        mv.addObject("message", "Hello World!,i am HelloWorldController.");
        mv.setViewName("hello");

        return mv;
    }
}

而另一个是通过注解实现的HelloWorld Handler:

@Controller
public class HelloWorldAnnotation{

    @RequestMapping(value="/helloWorldAnnotation")
    public String hello(ModelMap model){

        model.addAttribute("message", "Hello, World!I am HelloWorldAnnotation.");

        return "hello";
    }
}

这两种方式就是分别通过SimpleControllerHandlerAdapte和AnnotationMethodHandlerAdapter处理的,那这样一说就很明白了。另外这三个个Handler代理都实现了HandlerAdapter接口,就是Spring MVC规定了Handler代理的规则,分别有以下定义方法:

public interface HandlerAdapter {
    //判断处理适配器是不是支持该Handler
    boolean supports(Object handler);
    //调用对应的Handler中适配到的方法,并返回一个ModelView
    ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
    //这个暂时还没看懂具体想干什么(不是重点,暂时放下)
    long getLastModified(HttpServletRequest request, Object handler);
}

其中判断是否找到合适的Handler代理就靠这个supports方法的具体实现,如果适配成功,这个代理会替这个Handler实现业务路基处理。再简单这三个代理的supports实现:

//HttpRequestHandlerAdapter
@Override
public boolean supports(Object handler) {
return (handler instanceof HttpRequestHandler);
}

//SimpleControllerHandlerAdapte
@Override
public boolean supports(Object handler) {
    return (handler instanceof Controller);
}

//AnnotationMethodHandlerAdapter
@Override
public boolean supports(Object handler) {
    return getMethodResolver(handler).hasHandlerMethods();
}

再来简单分别说说以上三个代理对handle方法的实现:

HttpRequestHandlerAdapter和SimpleControllerHandlerAdapte都是直接调用handler的handleRequest方法,而AnnotationMethodHandlerAdapter稍微复杂一点,它是通过注释和反射获取相关自定义信息,进行匹配和封装,具体可自行参考其源码。

Handler

这就是自己实现的具体业务处理类了,上文提到很多,不用多说了。

ModelAndView

通过handler代理完成业务流程后返回一个ModelAndView对象,从名称就大概可以知道这是一个装载的数据模型(Model)和数据视图的对象(View)。

Model

从源码可以看出,model集成了LinkedHashMap<String,Object>类,这个model对象装载了所有在Handler响应给页面的数据。例如在我自己例子中的message数据:

model.addAttribute("message", "Hello, World!I am HelloWorldAnnotation.");

这些数据将会在页面上通过JSTL获取。

View

View接口表示一个响应给用户的视图,例如jsp文件,pdf文件,html文件等,该接口定义如下:

public interface View {
    //HttpServletRequest中的属性名,其值为响应状态码
    String RESPONSE_STATUS_ATTRIBUTE = View.class.getName() + ".responseStatus";
    //HttpServletRequest中的属性名,前一篇文章用到了该变量,它的对应值是请求路径中的变量,及@PathVariable注解的变量
    String PATH_VARIABLES = View.class.getName() + ".pathVariables";
    //该视图的ContentType
    String SELECTED_CONTENT_TYPE = View.class.getName() + ".selectedContentType";
    //获取该视图ContentType
    String getContentType();
    //渲染该视图
    void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception;
}

该接口只有两个方法定义,分别表明该视图的ContentType和如何被渲染。Spring中提供了丰富的视图支持,并且可以自定义视图。

ViewResolver

ViewResolver接口定义了如何通过view 名称来解析对应View实例的行为。例如在我自己的一个注解Handler实现里面,我返回的是“hello”view name字符串,意思就是响应到对应的hello.jsp视图(在springmvc-servlet.xml配置文件定义了):

//controller
@RequestMapping(value="/helloWorldAnnotation")
public String hello(ModelMap model){
    …
    return "hello";
}

springmvc-servlet.xml:

<!-- ViewResolver -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/jsp/" />
        <property name="suffix" value=".jsp" />
</bean>

在这里,我选择了默认Spring MVC JSP的实现类InternalResourceViewResolver。再来看看ViewResolver的接口定义:

public interface ViewResolver {
    View resolveViewName(String viewName, Locale locale) throws Exception;
}

该接口只有一个方法,通过view name 解析出View。还是以我例子为准,通过“hello”view name字符串,通过ViewResolver. resolveViewName方法生成View实例。再通过View实例的render方法渲染该视图,剩下的具体细节可自行学习。

总结

 

两天学习下来,终于对Spring MVC有个大概的了解。毕竟是一个通用的框架,除了默认的实现,Spring MVC框架还定义了大量的标准可供用户自定义实现,整体也算是采用了Open-Closed原则,扩展性好,但有不失整体优雅。

时间: 2024-10-11 07:16:35

【WEB】初探Spring MVC框架的相关文章

[email&#160;protected] 深入学习之——初探spring mvc

一.简介 Spring MVC是Spring框架的最重要的模块之一,它构建于Spring IoC容器之上,大量使用容器的特性简化其配置.MVC模式消除了业务逻辑与UI的耦合.模式负责封装视图展示的应用数据:视图只显示数据,不包含任何业务逻辑:控制器负责接收用户请求并调用后端服务进行业务处理,处理之后,后端服务可能返回某些数据供视图显示.其核心思想是分离业务逻辑与UI,使系统能够独立修改,互不影响. Spring MVC应用,模式通常由服务层处理和持续层存储的领域对象组成.视图通常是用Java标准

搭建基于spring MVC框架 + RESTful架构风格技术总结

实战篇: 在SpringMVC框架中搭建RESTful架构风格来完成客户端与服务器端的低耦合度.可扩展性.高并发与大数据流量的访问. 用RESTful架构的创建步骤: 1.创建一个全新的Web工程 2.导包,导入所需要的所有第三方jar包.(springMVC+Hibernate的基本包是必须的) 3.作配置,针对不同的项目需求和不同的搭建设计,开发人员可以按照自己的编码风格来设计符合项目开发具体 应该用多少篇配置文件.但是这几篇配置文件是必不可少的: 3-1.web.xml配置文件:最基本的配

Spring MVC 框架搭建及详解

一.Spring MVC环境搭建:(Spring 2.5.6 + Hibernate 3.2.0) 1. jar包引入 Spring 2.5.6:spring.jar.spring-webmvc.jar.commons-logging.jar.cglib-nodep-2.1_3.jar Hibernate 3.6.8:hibernate3.jar.hibernate-jpa-2.0-api-1.0.1.Final.jar.antlr-2.7.6.jar.commons-collections-3

Spring MVC 框架搭建及具体解释

如今主流的Web MVC框架除了Struts这个主力 外.其次就是Spring MVC了,因此这也是作为一名程序猿需要掌握的主流框架.框架选择多了.应对多变的需求和业务时,可实行的方案自然就多了. 只是要想灵活运用Spring MVC来应对大多数的Web开发,就必需要掌握它的配置及原理. 一.Spring MVC环境搭建:(Spring 2.5.6 + Hibernate 3.2.0) 1. jar包引入 Spring 2.5.6:spring.jar.spring-webmvc.jar.com

Spring MVC框架搭建

Spring MVC篇一.搭建Spring MVC框架 本项目旨在搭建一个简单的Spring MVC框架,了解Spring MVC的基础配置等内容. 一.项目结构 本项目使用idea intellij创建,配合maven管理.整体的目录结构如图: 其中java文件夹是sources文件夹,resources是资源文件夹.spring文件夹里是Spring上下文配置和Spring MVC配置文件. 需要注意的是,项目自动生成以后会有两个web文件目录,一个是web文件夹(我这里已经删除了),另一个

Spring MVC篇一、搭建Spring MVC框架

本项目旨在搭建一个简单的Spring MVC框架,了解Spring MVC的基础配置等内容. 一.项目结构 本项目使用idea intellij创建,配合maven管理.整体的目录结构如图: 其中java文件夹是sources文件夹,resources是资源文件夹.spring文件夹里是Spring上下文配置和Spring MVC配置文件. 需要注意的是,项目自动生成以后会有两个web文件目录,一个是web文件夹(我这里已经删除了),另一个是默认的webapp文件夹.我这里使用默认的目录,也就是

spring MVC 框架的搭建(myeclipse +maven)--(上)

spring mvc 的框架搭建过程如下,这个框架建议新手去看,因为搭建的是一个比较简单的矿建,当然里面涉及到的spring +hibernate相关的知识,是值得学习的. 这个项目是基于maven的主要是maven 能够很好的帮我们管理jar 包. spring mvc 框架搭建过程如下: 第一步:使用maven引入springMVC所需要的jar包 引入与springmvc相关的jar包,在pom.xml的<dependencise>标签下添加以下3个jar包 (1) spring-web

Spring MVC 框架的架包分析,功能作用,优点

由于刚搭建完一个MVC框架,决定分享一下我搭建过程中学习到的一些东西.我觉得不管你是个初级程序员还是高级程序员抑或是软件架构师,在学习和了解一个框架的时候,首先都应该知道的是这个框架的原理和与其有关jar的作用.关系.这篇文章总结一下spring框架的相关知识. 一.spirng的简介(高手可以跳过) Spring是一个开源框架,它由Rod Johnson创建.它是为了解决企业应用开发的复杂性而创建的.Spring使用基本的JavaBean来完成以前只可能由EJB完成的事情.然而,Spring的

Spring MVC框架实例

Spring  MVC 背景介绍 Spring 框架提供了构建 Web 应用程序的全功能 MVC 模块.使用 Spring 可插入的 MVC 架构,可以选择是使用内置的 Spring Web 框架还是 Struts 这样的 Web 框架.通过策略接口,Spring 框架是高度可配置的,而且包含多种视图技术,例如 JavaServer Pages(JSP)技术.Velocity.Tiles.iText 和 POI.Spring MVC 框架并不知道使用的视图,所以不会强迫您只使用 JSP 技术.S