文章源自JAVA秀-https://www.javaxiu.com/19919.html
前一章节回顾: 通过前一些章节的了解,我们大致了解了spring的运行的基本机制。但是好像还是和我们常用的场景不太一样,我们常用的场景是打成一个war包,然后丢到tomcat的webapps目录下面,然后tomcat会自动的帮我们启动web应用。那么一个应用请求时如何被我的controller处理的呢?这些问题对于我们仿佛都是一个黑盒,后续的这几个章节我们都会重点分析并弄清楚这个问题。那么在深入了解原理之前,我们首先了解一下servlet是什么,一些基本用法,以及servlet的核心工作原理。 文章源自JAVA秀-https://www.javaxiu.com/19919.html
文章源自JAVA秀-https://www.javaxiu.com/19919.html
Java Servlet 是运行在 Web 服务器或应用服务器上的程序,它是作为来自 Web 浏览器或其他 HTTP 客户端的请求和 HTTP 服务器上的数据库或应用程序之间的中间层。在spring没有出现之前,我们开发java服务程序的时候,通常使用的是servlet技术。对于servlet有了解的同学可以略过这一章节,对于不了解servlet的同学可以简单的学一下servlet的基本使用,以及基本的工作原理。那么怎么理解servlet是什么呢?可以理解为spring的controller类,用来处理一类资源的服务请求的servlet处理类。文章源自JAVA秀-https://www.javaxiu.com/19919.html
1.Servlet的基本使用
[1] pom文件添加servlet相关的依赖包文章源自JAVA秀-https://www.javaxiu.com/19919.html
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
[2] web.xml文件的配置文章源自JAVA秀-https://www.javaxiu.com/19919.html
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<!-- utf8统一处理 -->
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
//设置web.xml的url与servlet的映射关系(也就是由哪个servlet处理哪个url请求,类似于spring的controller里面加上@RequestMapping注解,绑定controller和url请求关系)。
<servlet>
<servlet-name>minesoft-tutorial</servlet-name>
<servlet-class>com.minesoft.tutorial.servlet.UserServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>minesoft-tutorial</servlet-name>
<url-pattern>/user</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
</web-app>
[3] 创建一个如下的UserServlet类文章源自JAVA秀-https://www.javaxiu.com/19919.html
public class UserServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("doPost ---------------");
System.out.println(req.getMethod());
System.out.println(req.getRequestURI());
System.out.println(req.getServletPath());
System.out.println(req.getServerPort());
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("doGet ---------------");
System.out.println(req.getMethod());
System.out.println(req.getRequestURI());
System.out.println(req.getServletPath());
System.out.println(req.getServerPort());
resp.setContentType("text/json;charset=UTF-8");
resp.setCharacterEncoding("UTF-8");
PrintWriter out = resp.getWriter();
User user = new User();
user.setId(1000L);
user.setName("张山");
user.setIdentity("43057818787873628X");
user.setBankcard("36457736355363");
user.setMobile("16752652625");
user.setGender(2);
user.setAge(18);
String str = JSONObject.toJSONString(user);
out.println(str);
out.flush();
out.close();
}
}
完成上述的配置之后,我们将工程运行起来,然后前往浏览器地址栏输入http://localhost:8081/user,就能看到doGet中设置的json返回对象了。从上述过程,我们基本上了解了servlet的使用过程,同样的业务功能,只不过相对于spring而言开发更加复杂而已(同样也说明了spring的价值所在,大大的简化了我们的业务开发过程)。文章源自JAVA秀-https://www.javaxiu.com/19919.html
2.Servlet的核心工作过程(也就是HttpServlet模板类的模板方法)
我们知道,首先一个http请求经过浏览器的封装,然后经过硬件线路最终转发到服务器的tomcat容器。其次tomcat接收到这个请求之后,根据web.xml的相应的配置(也就是配置servlet-mapping,参见上面部分的servlet-mapping配置),最终转发到我们的业务Servlet类。再次这个Servlet类对应的doGet方法,doPost方法进行相应的业务处理。至于浏览器是如何封装一个http请求的,硬件线路是如何传输这个请求的,还有tomcat是如何转发给servlet的,这章节我们暂时不去做讨论,留到后续的tomcat的里面进行分析。我们只要知道经过前面一系列的处理,tomcat最终会把一个http请求委托给业务Servlet类的service方法即可。那么从service开始,是怎么一步一步的将这个http请求转给doGet,doPost进行处理的呢?下面我们将进行细致的分析:文章源自JAVA秀-https://www.javaxiu.com/19919.html
[1] tomcat调用servlet的service方法,处理一个http请求。文章源自JAVA秀-https://www.javaxiu.com/19919.html
@Override
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException
{
HttpServletRequest request;
HttpServletResponse response;
if (!(req instanceof HttpServletRequest &&
res instanceof HttpServletResponse)) {
throw new ServletException("non-HTTP request or response");
}
request = (HttpServletRequest) req;
response = (HttpServletResponse) res;
service(request, response);
}
[2] service方法又将http请求委托给另外一个service方法处理,这个方法将http请求进行分类处理。类型包括GET,POST,PUT,DELTE,OPTIONS,TRACE等等。文章源自JAVA秀-https://www.javaxiu.com/19919.html
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)) {
//如果是POST方法
doPost(req, resp);
} else if (method.equals(METHOD_PUT)) {
//如果是PUT方法
doPut(req, resp);
} else if (method.equals(METHOD_DELETE)) {
//如果是DELETE方法
doDelete(req, resp);
} else if (method.equals(METHOD_OPTIONS)) {
//如果是OPTIONS方法
doOptions(req,resp);
} else if (method.equals(METHOD_TRACE)) {
//如果是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);
}
}
[3] 如果是GET方法,那么该请求会被交给doGet方法进行处理文章源自JAVA秀-https://www.javaxiu.com/19919.html
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);
}
}
而因为我们的UserServlet业务Servlet重写了doGet方法,所以实际运行的时候不会调用上面父类的doGet方法,而是调用子类的doGet方法。文章源自JAVA秀-https://www.javaxiu.com/19919.html
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("doGet ---------------");
System.out.println(req.getMethod());
System.out.println(req.getRequestURI());
System.out.println(req.getServletPath());
System.out.println(req.getServerPort());
resp.setContentType("text/json;charset=UTF-8");
resp.setCharacterEncoding("UTF-8");
PrintWriter out = resp.getWriter();
User user = new User();
user.setId(1000L);
user.setName("张山");
user.setIdentity("43057818787873628X");
user.setBankcard("36457736355363");
user.setMobile("16752652625");
user.setGender(2);
user.setAge(18);
String str = JSONObject.toJSONString(user);
out.println(str);
out.flush();
out.close();
}
通过上述的过程,我们基本上知道了一个http请求是如何被tomcat接受到后,最终被交给用户的具体的业务处理方法处理的了。文章源自JAVA秀-https://www.javaxiu.com/19919.html
文章源自JAVA秀-https://www.javaxiu.com/19919.html
更多知识请关注公众号文章源自JAVA秀-https://www.javaxiu.com/19919.html

评论