JavaWeb——Servlet执行流程详解
JavaWeb——Servlet执行流程详解 说起Servlet的执行流程,就不得不先提及一个前提,Servlet技术的核心是Servlet,它是所有Servlet类必须直接或间接实现的一个接口,下面看一下Servlet的具体结构。 一、首先,先来系统的了解一下Servlet的结构。Servlet最顶层的接口——Servlet 最顶层的Servlet接口中有三个比较重要的方法...
·
JavaWeb——Servlet执行流程详解
说起Servlet的执行流程,就不得不先提及一个前提,Servlet技术的核心是Servlet,它是所有Servlet类必须直接或间接实现的一个接口,下面看一下Servlet的具体结构。
一、首先,先来系统的了解一下Servlet的结构。
Servlet最顶层的接口——Servlet
最顶层的Servlet接口中有三个比较重要的方法init(ServletConfig)、service(req,resp)和destroy(),其中
init(ServletConfig):表示当该Servlet第一次被请求时,Servlet容器回调用该方法,后续的请求不会再被调用,可以利用该方法进行相应的初始化功能(ServletConfig可以与配置文件中的init-param相对应)
service:每当请求Servlet时,Servlet容器就会调用这个方法。而该方法在该接口的其他子接口被具体化了。
destory:当要销毁Servlet时,Servlet容器就会调用该方法。通常在卸载程序,或者关闭Servlet容器就回发生调用销毁方法,一般会在这里写一下清除工作的代码。
实现Servlet接口的抽象类——GenericServlet
由于要想编写Servlet就必须通过实现Servlet接口,如果是直接实现Servlet接口就必须实现Servlet接口中所定义的所有方法,即使一些方法并没有什么作用也必须得实现,因此产生了GenericServlet抽象类
GenericServlet抽象类
虽然成为抽象类,但其实现了Servlet接口中的所有方法的默认实现,因此编写Servlet不需要再将所有的方法都实现,而是根据需求实现与业务相关的方法即可。并且,GenericServlet将ServletConfig对象由系统来维护,不需要程序员手动的维护了。
实现Servlet最重要的主角——HttpServlet
HttpServlet抽象类
(实际上是没有抽象方法的,因此自定义类继承HttpServlet时可以一个方法也不覆写)是GenericServlet抽象类的子),其最大的作用,就是将service()方法进行了全面的升级。可以看一下HttpServlet中service()的源代码
@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);
}
可以看到,HttpServlet通过继承GenericServlet的service()方法将ServletRequest、ServletResponse对象转换为HttpServletRequest、HttpServletResponse对象,并最终都引用了HttpServlet类自身的 service(HttpServletRequest request, HttpServletResponse response);因此,此时的核心就是这个HttpServlet类中自己编写的service()方法
。
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);
}
}
由源码就可以看出,这个service()大体上所做的操作,就是根据http请求的类型,由service()方法进行分配,分配到对应的doXXX()方法中
(eg:发送的get请求,由service()分配至doGet()中进行下一步的操作)
最常用的doXXX()是doGet()
与doPost()
二、此时了解了Servlet的结构,接下来看一下Servlet的具体执行流程。
先上一张流程图
流程大体分为两个部分
1、通过url地址找到自定义类
①通过外部的HTTP协议请求(浏览器输入访问域名),访问到Tomcat服务器,携带了请求行、头、体
②Tomcat服务器访问web.xml,根据访问路径在<servlet-mapping>中查找与url中所对应的<url-pattern>,并通过<servlet-name>确定与该映射对应的<servlet>
③通过<servlet>中的<servlet-class>找到我们自定义的Servlet类(全限定类名)
2、根据请求方法及参数完成自定义Servlet的流程
①服务器找到对应全限定类名后,通过反射
创建对象,同时也创建了ServletConfig(存放了一些初始化信息,服务器只会创建一次servlet对象,因此ServletConfig只有一个
)
a)由于自定义的Servlet类继承了HttpServlet,因此若自定义Servlet覆写了init()方法,在该Servlet第一次创建
的时候,会首先执行init()方法。
b)若自定义Servlet没有覆写init()方法,就会在其父类HttpServlet中找,而HttpServlet中也没有init(),最终会在HttpServlet的父类GenericServlet中找到init()方法并执行。(GenericServlet类中的init()是一个空方法,什么也不会执行
)
②服务器先创建两个对象:ServletRequest请求对象
与ServletResponse响应对象
,用来封装接收浏览器的请求数据
和向浏览器发送的相应数据
,
a)服务器会默认的在自定义Servlet类中寻找service(ServletRequest req,ServletResponse resp)方法,但自定义类中一般都不会实现这个方法,因此会在其父类HttpServlet中寻找。
b)在父类的HttpServlet中发现有service(req,resp)方法,将创建好的两个对象传入,并在该service中将这两个对象强转为HttpServletRequest和HttpServletResponse,调用HttpServlet内部的另一个service()方法(这个方法不是继承自GenericServlet的,而是属于HttpServlet的
)
c)执行service(HttpServletRequest req, HttpServletResponse resp)方法,该方法内部对请求的方式进行判断,执行doGet()或doPost()方法,而此时doGet()或者doPost()已经被自定义Servlet覆写,因此会继续执行自定义类中对应覆写的方法。(自定义类覆写doXXX()方法时一定不能调用super().doXXX()方法,若调用会导致405错误
)
d)在自定义类中对应覆写的方法执行完后,将数据响应通过resp返回给浏览器。
总结一下流程为
流程总结参考
更多推荐
已为社区贡献1条内容
所有评论(0)