SpringMvc简述

1、概述:

继上一篇,这篇写SpringMvc,此篇博文将以不同的视觉透视SpringMvc,将以数据请求、接收处理和应答返回的过程介绍SpringMvc,看此篇博文需对Http协议、动态网页(Jsp或模板引擎)、数据库、字符集、网络IO(Tcp)、Web服务器(Tomcat或Jetty)有一定的了解。

2、数据请求:

我们知道服务器之间通信(即数据传输),是在Internet网上(也有其它,现在不论),OSI的7层协议分别是物理层、数据链路层、网络层、传输层、会话层、表示层和应用层,我们通常是在传输层和应用层编码开发。

看到这里可能会问,传输层和应用层好像与SpringMvc没多大关系吧!因为基于SpringMvc开发时,我们在Controller层接收应答数据都是以函数接口形式。

我想说能这样Happy编码,完全是Web容器(Tomcat或Jetty),及SpringMvc的功劳,否则,夸张一点说,50%后端Web程序员将转行。那Web容器和SpringMvc在此过程到底干了些什么?

2.1、Web容器:

在看下面内容之前,需明白基于操作系统(windows/linux/unix)开发时,如果没有做到驱动层,或者使用原始Socket,我们通常使用传输层的Tcp协议,进行网络通信开发,Web容器也不例外,应用层使用Http协议,传输层使用Tcp协议。

Http协议通常用于Web开发,从浏览器发出的大多数请求是基于Http协议(可用WebSocket),Http协议是一种超文本传输协议,即可见字符,做过Tcp Socket通信的人都知道,IO都是Byte流,那它如何变成Http超文本呢?

其实由Byte流转变成Http超文本是由Web容器完成,并且会将Http超文本完全或部分映射成本地编码对象,以Java和Tomcat为例,最终会映射成HttpServletRequestHttpServletResponse,到此Web容器已经完成了两个核心功能:

1、完成网络通信;

2、完成数据的转换;

以下内容全是基于Java和Tomcat简述。

2.2、SpringMvc:

Tomcat已经将数据包转成HttpServletRequest和HttpServletResponse,现在只需要读取值,据值定义逻辑处理,要实现某个功能逻辑,有不同编码设计方式,若没有一个约定,因人而异,各有不同,最终开发维护成本会很高,基于这个SpringMvc应运而生。

SpringMvc即是一种设计模式,也是一种编码规范,可分为两部分Spring和DispatcherServlet,DispatcherServlet继承自Servlet(动态网页开发技术),据多态原理,可被Tomcat加载到内存,为了更好的理解,看一段注解方式启动SpringMvc代码。

public class WebInitializer implements WebApplicationInitializer {
    public void onStartup(ServletContext servletContext) throws ServletException {
        //Spring
        AnnotationConfigWebApplicationContext app = new AnnotationConfigWebApplicationContext();
        app.register(SpringMvcConfig.class);
        

        //DispatcherServlet
        ServletRegistration.Dynamic dynamic = servletContext.addServlet("dispatcher", new DispatcherServlet(app));
        
        dynamic.addMapping("/");
        dynamic.setLoadOnStartup(1);
    }
}

DispatcherServlet类图:

这里写图片描述

至于Spring请看上一篇博文,到此必需明白,Tomcat定义Servlet接口规定输入输出参数规范,将实现类或其子类加载到内存,而HttpServlet再一次对Http协议进行映射封装(函数接口的形式),如:

public abstract class HttpServlet extends GenericServlet {

    private static final long serialVersionUID = 1L;

    private static final String METHOD_DELETE = "DELETE";
    private static final String METHOD_HEAD = "HEAD";
    private static final String METHOD_GET = "GET";
    private static final String METHOD_OPTIONS = "OPTIONS";
    private static final String METHOD_POST = "POST";
    private static final String METHOD_PUT = "PUT";
    private static final String METHOD_TRACE = "TRACE";

    private static final String HEADER_IFMODSINCE = "If-Modified-Since";
    private static final String HEADER_LASTMOD = "Last-Modified";

    private static final String LSTRING_FILE =
        "javax.servlet.http.LocalStrings";
    private static final ResourceBundle lStrings =
        ResourceBundle.getBundle(LSTRING_FILE);


    /**
     * Does nothing, because this is an abstract class.
     */
    public HttpServlet() {
        // NOOP
    }


    //Http协议参数映射封装
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException

    {
        String protocol = req.getProtocol();
        String msg = lStrings.getString("http.method_get_not_supported");
        if (protocol.endsWith("1.1")) {
            resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
        } else {
            resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
        }
    }
     
    ... 

到现在为止没有说MVC,MVC是一种设计模式,以Web开发来说,M:数据层、V:视图层、C:逻辑层,而DispatcherServlet和Spring就是实现MVC的手段,即SpringMvc。

2.3、DispatcherServlet和Spring(即SpringMvc):

Tomcat网络IO的Byte流数据,将映射成Java对象,通过HttpServletRequest和HttpServletResponse两个参数对象,传给HttpServlet的方法(据Http协议请求行指定请求方法),如:

protected void doPost(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException {

        String protocol = req.getProtocol();
        String msg = lStrings.getString("http.method_post_not_supported");
        if (protocol.endsWith("1.1")) {
            resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
        } else {
            resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
        }
    }

HttpServletRequest主要包含Http协议的请求行、请求头和请求体,和IO输入流;

HttpServletResponse主要包含Http协议的响应行、响应头和响应体,和IO输出流;

DispatcherServlet将会调用Spring容器提供的对象进行逻辑处理,完成大多数约定编码(即设计模式),最终大多数使用者仅需从Controller开始编码。

3、数据处理:

到此必需明白数据以HttpServletRequest输入,以HttpServletResponse输出,否则不要往下看了!

DispatcherServlet处理数据方式分为两种:

1、自定义;

2、彼定义;

3.1、自定义:

自定义约束规范,完成大多数统一处理,最终调用彼定义的接口函数,下面详细来述此过程。

早期基于Tomcat开发的人都知道,继承HttpServlet开发,一Uri映射一HttpServlet实体对象,如:

<servlet>
    <servlet-name>servletOne</servlet-name>
    <servlet-class>cn.sd.ServletOne</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>servletOne</servlet-name>
    <url-pattern>/servletOne</url-pattern>
</servlet-mapping>

<servlet>
    <servlet-name>servletTwo</servlet-name>
    <servlet-class>cn.sd.ServletTwo</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>servletTwo</servlet-name>
    <url-pattern>/servletTwo</url-pattern>
 </servlet-mapping>

而DispatcherServlet是以Uri映射函数的形式完成此功能,即一Uri映射一函数,这个映射过程即自定义处理,也是DispatcherServlet的核心所在,先抛出一些在此过程DispatcherServlet定义的相关术语,处理器映射器、拦截器、处理器适配器、参数转换器。

处理器映射器完成Uri与函数的配对关系(key/value),拦截器利用SpringAop拦截函数、处理器适配器决定函数如何被调用(适配器设计模式)、参数转换器将Http协议请求参数转换成Java函数参数,最后我们可以在Controller层Happy编码。

3.2、彼定义:

彼定义,即你自由编码的地方,但这里通常还是要遵守SpringMvc的规范,否则别人看你代码,将会fuck。SpringMvc定义了Controller层、Service层、持久层(如Mybatis)和视图层(Jsp/Freemaker/Thymeleaf),它们将会被Spring容器统一管理。

这里补充一点,上面写的全部映射部分映射,Http协议请求行的Uri和Body都能以Key/Value、Json字符、或自定义格式传递参数,数据量不大,一次能读取全部映射,另一种情况如果数据量很大,或者文件上传,就不能全部转换,或不需要转换。

最后就是视图层,现在浏览器是基于Html、Js、Css渲染显示界面,虽说现在流行前后分离,但后端有时还是需要,即要界面开发,也要拿到Java数据,有点不厚道,视图层的出现就是为了解决此问题,Jsp最后会转成Servlet,Freemaker和Thymeleaf字符替换,Jsp最终应该是要转向Response(这段原码没有看过)。

4、应答返回:

应答即DispatcherServlet,把Controller层函数的返回值,或直接把填冲进HttpServletResponse数据,转换成Http协议数据,即响应行、响应头、响应体,最后交由Tomcat应答输出。

最后来一张SpringMvc执行流程图(非我画),助于理解。

用户请求不是直接到达DispatcherServlet,而是由Tomcat读取数据,解析请求行的Uri,找到对应的DispatcherServlet调用执行,完成相应逻辑后,再由Tomcat输出数据,Tomcat调用DispatcherServlet之前可以执行过滤器(aop思想,函数回调方式,如:统一转码)。另外前后分离开发时无视图层。

可能有些人不明白Tomcat容器是如何加载DispatcherServlet,早期Xml时是去读取包下的Web.xml进行加载,基于Java注解开发是去读取META-INF/services/javax.servlet.ServletContainerInitializer文件,读取感兴趣的类加载,如:

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值