-
servlet与tomcat
1、servlet与servlet容器
(1)servlet本质
前方高能,请注意、注意、注意。。。重要的事情说三遍,servlet本质就是一个Java接口 ,目的在于定义一套处理网络请求的规范,如下所示:
package javax.servlet; import java.io.IOException; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; public interface Servlet { void init(ServletConfig arg0) throws ServletException; ServletConfig getServletConfig(); void service(ServletRequest arg0, ServletResponse arg1) throws ServletException, IOException; String getServletInfo(); void destroy(); }
所有实现servlet接口的类,都要实现接口中的五个方法,其中最主要的是两个生命周期方法 init()和destroy()、处理请求的service(),即:
- 初始化的作用;
- 销毁后的作用;
- 收到请求后需要做什么。
init() 和 destroy()方法只执行一次, 即servlet的生命周期---创建和销毁,而service()方法每次有新请求到达时都会调用,即处理处理实际业务。
(2)servlet容器
全称server applet,意为服务程序。主要作用是给上级容器(Tomcat)提供doGet()和doPost()等方法。其生命周期实例化、初始化、调用、销毁受控于Tomcat容器。
(3)request/response
request:浏览器发起http请求,请求到达tomcat,经tomcat封装成了request对象(将请求头、请求地址、请求参数等进行了封装);
response:浏览器发起http请求到达tomcat容器时,产生一个空的response对象,http请求数据经过servlet处理,将处理后结果封装成response对象,经过tomcat处理后,组装成HTTP响应返回给浏览器。
(4)web容器
可以部署多个WEB应用程序的环境。Tomcat容器属于web容器的一种,web容器还包括weblogic容器、JBoss容器等;而Tcomcat、webLogic等包含servlet容器。
注:三层架构实质是对servlet的拆分,目的在于解耦合。
2、tomcat
(1)tomcat程序入口main()
main方法是启动一个java程序的入口,任何程序都会有自己的main方法,tomcat是一个WEB容器,也不例外:
//TODO 以下为伪代码,目的在于说明tomcat执行原理 public static void main(String args[]) { //TODO 初始化运行环境,载入需要的jar包,读取conf/server.xml,生成相应的运行对象: if (daemon == null) { Bootstrap bootstrap = new Bootstrap(); try { bootstrap.init();//初始化守护进程 } catch (Throwable t) { return; } daemon = bootstrap; } //TODO 装载,开始运行。 try { String command = "start"; if (command.equals("startd")) { daemon.load(args); daemon.start();//启动Tomcat } else if (command.equals("stopd")) { args[args.length - 1] = "stop"; daemon.stop();//停止Tomcat守护进程 } } catch (Throwable t) { } }
(2)tomcat创建的resques和response
(3)tomcat对servlet接口的实现
abstract class GenericServlet implements Servlet, ServletConfig,Serializable
abstract class HttpServlet extends GenericServlet
public abstract class HttpServlet extends GenericServlet { 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(405, msg); } else { resp.sendError(400, msg); } } //TODO doHead doPut doDelete 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(405, msg); } else { resp.sendError(400, msg); } } protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String method = req.getMethod(); long errMsg; if (method.equals("GET")) { errMsg = this.getLastModified(req); if (errMsg == -1L) { this.doGet(req, resp); } else { long ifModifiedSince; try { ifModifiedSince = req.getDateHeader("If-Modified-Since"); } catch (IllegalArgumentException arg8) { ifModifiedSince = -1L; } if (ifModifiedSince < errMsg / 1000L * 1000L) { this.maybeSetLastModified(resp, errMsg); this.doGet(req, resp); } else { resp.setStatus(304); } } } else if (method.equals("POST")) { this.doPost(req, resp); } else { String errMsg1 = lStrings.getString("http.method_not_implemented"); Object[] errArgs = new Object[] { method }; errMsg1 = MessageFormat.format(errMsg1, errArgs); resp.sendError(501, errMsg1); } } public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { HttpServletRequest request; HttpServletResponse response; try { request = (HttpServletRequest) req; response = (HttpServletResponse) res; } catch (ClassCastException arg5) { throw new ServletException(lStrings.getString("http.non_http")); } this.service(request, response); } }
部署的过程其实就是解析 xml 实例化对象,并触发和处理容器及组件对应生命周期事件的过程。在 Tomcat 中,一个 Context 实例就代表一个 Web 应用程序,所以部署的第一步就是创建一个 StandardContext 对象。在创建时 HostConfig 首先会查找 Context 描述符,它可能在两个位置:
- $CATALINA_BASE/conf/<engine>/<host>/[webappname].xml
- $CATALINA_BASE/webapps/webappname/META_INF/context.xml
如果两个位置都不存在此文件,则使用 conf/context.xml 默认配置。
Context 实例化后会触发 init 和 start 生命周期事件:
- init - 会创建用于解析 context.xml 和 web.xml 的工具 Digester 的实例,并解析context.xml
- start - 则会根据 web.xml 部署描述符实例化 Servlet、Filter、Listener 等 Web 组件
3、重定向与请求转发
(1)定义及区别
重定向:
1.可以理解为是客户端行为,客户端发起一次请求,服务器端给出一次响应,但这个响应包含下一次客户端需要访问的服务器端处理程序的地址,客户端再次发起请求,将会得到处理结果,也就意味着重定向客户端至少发起两次请求。
2.当使用了重定向跳转页面后,在其客户端路径栏显示的是重定向的路径。
3.重定向可以跨域访问,而转发是在web服务器内部进行的,不能跨域访问。
请求转发:
1.可以理解是服务器端行为,客户端发起一次请求,在整个服务器端可以被多次传递,但都是由服务器端的处理程序传递给另一个处理程序,无论这个请求经历过多少个处理程序,始终都是同一个请求。
2.可共享request域(request.setAttribute(), request.getAttribute())中的数据,重定向获取不到request域中的数据,只能用session。
3.forward()相对高效,在可以满足需要时,尽量使用RequestDispatcher.forward()方法。
(2)核心原理分析
HTTP协议规定了一种重定向机制,重定向的运作流程如下:
1)用户在浏览器端输入特定URL,请求访问服务器端的某个组件。
2)服务器端的组件返回一个状态码为302的响应结果,该响应结果的含义为:让浏览器端再请求访问另一个Web组件,在响应结果中提供了另一个Web组件的URL。另一个Web组件有可能在同一个Web服务器上,也有可能不再同一个Web服务器上。
3)当浏览器端接收到这种响应结果后,再立即自动请求访问另一个Web组件。
4)浏览器端接收到另一个Web组件的响应结果。
源组件和目标组件不共享同一个ServletRequest对象,因此不共享请求范围内的共享数据。如果以“/”开头,表示相对于当前服务器根路径的URL,如果以http://开头,表示一个完整的URL。
感谢阅读,参考了不少大佬资料,如需转载,请注明出处 https://www.cnblogs.com/huyangshu-fs/p/13173474.html