[springMvc] 源码分析笔记(一)
1. Servlet 结构图

2. servlet接口
public interface Servlet {
//init方法在容器启动时被容器调用(当load-on-startup设置为负数或者不设置时会在Servlet第一次用到时才被调用),只调用一次
void init(ServletConfig var1) throws ServletException;
//
ServletConfig getServletConfig();
//service方法用于具体处理一个请求
void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
//获取Servlet相关的信息,如作者、版权等,需要自己实现,默认返回空字符串
String getServletInfo();
//主要用于在Servlet销毁(一般指关闭服务器)时释放一些资源,也只会调用一次
void destroy();
}
Init方法被调用时会接收到一个 ServletConfig类型的参数,是容器传进去的。 ServletConfig顾名思义指的是 Servlet的配置,我们在 web.xml中定义 Servlet时通过 init-param标签 配置的参数就是通过ServletConfig来保存的,比如,定义Spring MVC的Servlet时指定配置 文件位置的contextConfigLocation参数就保存在ServletConfig中,例如下面的配置:
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:applicationContext.xml,classpath:webmvc-config.xml
</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
Tomcat 中 Servlet 的 init 方法是在 org.apache.catalina.core.StandardWrapper 的 initServlet 方法中调用的。
2.1 ServletConfig 接口
public interface ServletConfig {
//获取Servlet的名字,也就是我们在web.xml中定义的servlet-name
String getServletName();
//ServletContext代表 的是我们这个应用本身
ServletContext getServletContext();
//用于获取init-param配置的参数
String getInitParameter(String var1);
//用于获取配置 的所有init-param的名字集合
Enumeration<String> getInitParameterNames();
}
2.2 GenericServlet
GenericServlet是Servlet的默认实现,主要做了三件事:①实现了 SbrvletConfig接口,我 们可以直接调用ServletConfig里面的方法;②提供了无参的ink方法;③提供了 log方法。
2.3 HttpServlet
HttpServlet是 用 HTTP 协议实现的 Servlet的基类,写 Servlet时直接继承它就可以了, 不需要时从头实现 Servlet接口,我们要分析的 Spring MVC中 的 DispatcherServlet就是继承 的 HttpServlet。既然 HttpServlet是跟协议相关的,当然主要关心的是如何处理请求 ,所 以 HttpServlet主要重写了 service方法。在 service方法中首先将 ServletRequest和 ServletResponse 转换为 HttpServletRequest 和 HttpServletResponse, 然后根据 Http 请求的类型不同 将请求路由到不同的处理方法。
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
//如果请求不符合规范直接抛出异常
if(req instanceof HttpServletRequest && res instanceof HttpServletResponse) {
//转换类型
HttpServletRequest request = (HttpServletRequest)req;
HttpServletResponse response = (HttpServletResponse)res;
this.service(request, response);
} else {
throw new ServletException("non-HTTP request or response");
}
}
不同的请求路由到不同的处理方法
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
String method = req.getMethod(); if (method.equals(METHOD_GET)) {
long lastModified = getLastModified(req);
if (lastModified == -1) {
// servlet doesn't support if-modified-since, no reason
// to go through further expensive logic
doGet(req, resp);
} else {
long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
if (ifModifiedSince < lastModified) {
// If the servlet mod time is later, call doGet()
// Round down to the nearest second for a proper compare
// A ifModifiedSince of -1 will always be less
maybeSetLastModified(resp, lastModified);
doGet(req, resp);
} else {
resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
}
} } else if (method.equals(METHOD_HEAD)) {
long lastModified = getLastModified(req);
maybeSetLastModified(resp, lastModified);
doHead(req, resp); } else if (method.equals(METHOD_POST)) {
doPost(req, resp); } else if (method.equals(METHOD_PUT)) {
doPut(req, resp); } else if (method.equals(METHOD_DELETE)) {
doDelete(req, resp); } else if (method.equals(METHOD_OPTIONS)) {
doOptions(req,resp); } else if (method.equals(METHOD_TRACE)) {
doTrace(req,resp); } else {
//
// Note that this means NO servlet supports whatever
// method was requested, anywhere on this server.
// String errMsg = lStrings.getString("http.method_not_implemented");
Object[] errArgs = new Object[1];
errArgs[0] = method;
errMsg = MessageFormat.format(errMsg, errArgs); resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
}
}
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);
}
}
[springMvc] 源码分析笔记(一)的更多相关文章
- [springMvc] 源码分析笔记(二)
1.SpringMvc 中核心Servlet的继承结构图 2.HttpServletBean public abstract class HttpServletBean extends HttpSer ...
- [心得体会]SpringMVC源码分析
1. SpringMVC (1) springmvc 是什么? 前端控制器, 主要控制前端请求分配请求任务到service层获取数据后反馈到springmvc的view层进行包装返回给tomcat, ...
- 8、SpringMVC源码分析(3):分析ModelAndView的形成过程
首先,我们还是从DispatcherServlet.doDispatch(HttpServletRequest request, HttpServletResponse response) throw ...
- 7、SpringMVC源码分析(2):分析HandlerAdapter.handle方法,了解handler方法的调用细节以及@ModelAttribute注解
从上一篇 SpringMVC源码分析(1) 中我们了解到在DispatcherServlet.doDispatch方法中会通过 mv = ha.handle(processedRequest, res ...
- zeromq源码分析笔记之线程间收发命令(2)
在zeromq源码分析笔记之架构说到了zmq的整体架构,可以看到线程间通信包括两类,一类是用于收发命令,告知对象该调用什么方法去做什么事情,命令的结构由command_t结构体确定:另一类是socke ...
- springMVC源码分析--ViewNameMethodReturnValueHandler返回值处理器(三)
之前两篇博客springMVC源码分析--HandlerMethodReturnValueHandler返回值解析器(一)和springMVC源码分析--HandlerMethodReturnValu ...
- springMVC源码分析--HandlerMethodReturnValueHandlerComposite返回值解析器集合(二)
在上一篇博客springMVC源码分析--HandlerMethodReturnValueHandler返回值解析器(一)我们介绍了返回值解析器HandlerMethodReturnValueHand ...
- springMVC源码分析--RequestParamMethodArgumentResolver参数解析器(三)
之前两篇博客springMVC源码分析--HandlerMethodArgumentResolver参数解析器(一)和springMVC源码解析--HandlerMethodArgumentResol ...
- springMVC源码分析--访问请求执行ServletInvocableHandlerMethod和InvocableHandlerMethod
在之前一篇博客中springMVC源码分析--RequestMappingHandlerAdapter(五)我们已经简单的介绍到具体请求访问的执行某个Controller中的方法是在RequestMa ...
随机推荐
- audio google play()
<audio id="music" src="" preload loop="loop" autostart="true&q ...
- html5 css练习 定位布局
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8&qu ...
- 游戏引擎——cocos2d-x
Cocos2d-x是一个开源的移动2D游戏框架,MIT许可证下发布的.这是一个C++ Cocos2d-iPhone项目的版本.Cocos2d-X发展的重点是围绕Cocos2d跨平台,Cocos2d-x ...
- Linux基础命令---sar显示系统活动信息
sar sar指令用来收集.报告.保存系统的活动信息.sar命令将操作系统中选定的累积活动计数器的内容写入标准输出.会计系统根据参数“interval”.“count”中的值,写入以秒为单位的指定间隔 ...
- Oracle免安装绿色版-PLSQL连接报12154
在环境变量添加 TNS_ADMIN 值是你的免安装客户端中sqlnet.ora tnsnames.ora 所在的目录 参考地址:https://blog.csdn.net/feng_na/art ...
- ES6 Promise用法讲解
所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果. ES6 规定,Promise对象是一个构造函数,用来生成Promise实例. 下面代码创造了一个 ...
- vue项目创建过程
在使用vue-cli之前,请确认你的电脑已经安装了 node,建议版本在 8.0.0 以上 可以通过node -v 检查版本 1.安装 vue-cli (这里我们确认已安装过node) 1.使用 np ...
- Python中自定义filter用法
django中新建项目,在项目中新建app,自定义filter一般放到app中.结构目录如下: 1.先在APP中新建一个templatetags的django文件夹,文件夹中新建一个filter的py ...
- centos 时钟配置
centos 7 时钟配置: timedatectl 命令: [root@localhost ~]# timedatectl --help timedatectl [OPTIONS...] COMMA ...
- 在ubuntu的bash中循环执行脚本,并在内存不足时重启
#!/bin/bash date ma=`grep MemAvailable /proc/meminfo | awk '{print $2}'` echo MemAvailable = $ma run ...