Javaweb主要组件Servlet、Filter、Listener
1.Servlet
servlet接口:
public interface Servlet {
public void init(ServletConfig config) throws ServletException;
public ServletConfig getServletConfig();
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException;
public String getServletInfo();
public void destroy();
}
1. 什么是Servlet?
Servlet就是一个java接口,处理请求和发送响应的过程是由一种叫做Servlet的程序来完成的,并且Servlet是为了实现动态页面而衍生的东西。
2. Tomcat和Servlet的关系
①处表示Web服务器接收到客户端发出的HTTP请求后,转发给Servlet容器,同时把控制返回Servlet容器;
②处表示Servlet容器把响应对象ServletResponse中的处理结果转发给Web服务器,通知Web服务器以HTTP响应的方式把结果发送到客户端,同时把控制返回Web服务器
Tomcat是Web应用服务器,是一个servlet/Jsp容器,Tomcat 作为Servlet容器,它监听了端口负责处理客户请求,把请求传送给Servlet,并将Servlet的响应传送回给客户。
Java Servlet API是Servlet容器和Servlet之间的接口,它定义了Servlet的各种方法,还定义了Servlet容器传送给Servlet的对象类,其中最重要的是请求对象ServletRequest和响应对象ServletResponse这两个对象都是由Servlet容器在客户端调用Servlet时产生的,Servlet容器把客户请求信息封装在ServletRequest对象中,然后把这两个对象都传送给要调
用的Servlet,Servlet处理完后把响应结果写入ServletResponse,然后由Servlet容器把响应结果发送到客户端。
3. 创建Servlet的原理
- Servlet的生命周期
在web.xml的<servlet>
中添加一条配置信息<load-on-startup>5</load-on-startup>(默认为0)
,当值大于0时,容器在应用启动时就会初始化一个servlet对象,当是一个负数时或者没有指定时,则指示容器在该servlet被请求时才加载,也就是会执行初始化方法init(ServletConfig conf)。
最后服务器关闭时,才会销毁这个servlet对象,执行destroy()方法。
PS:Servlet是单例的,整个服务器就只创建一个同类型Servlet; HttpServlet与Servlet
查看源码,httpServlet继承了GenericServletpublic abstract class HttpServlet extends GenericServlet
GenericServlet的继承结构,实现了Servlet接口和ServletConfig接口
public abstract class GenericServlet implements Servlet, ServletConfig, java.io.Serializable { private static final long serialVersionUID = 1L; private transient ServletConfig config; public GenericServlet() { // NOOP } @Override public void destroy() { // NOOP by default } @Override public String getInitParameter(String name) { return getServletConfig().getInitParameter(name); } @Override public Enumeration<String> getInitParameterNames() { return getServletConfig().getInitParameterNames(); } @Override public ServletConfig getServletConfig() { return config; } @Override public ServletContext getServletContext() { return getServletConfig().getServletContext(); } @Override public String getServletInfo() { return ""; } @Override public void init(ServletConfig config) throws ServletException { this.config = config; this.init(); } public void init() throws ServletException { // NOOP by default } public void log(String msg) { getServletContext().log(getServletName() + ": " + msg); } public void log(String message, Throwable t) { getServletContext().log(getServletName() + ": " + message, t); } @Override public abstract void service(ServletRequest req, ServletResponse res) throws ServletException, IOException; @Override public String getServletName() { return config.getServletName(); }
ServletConfig接口的代码
public interface ServletConfig { public String getServletName(); public ServletContext getServletContext(); public String getInitParameter(String name); public Enumeration<String> getInitParameterNames(); }
由Servlet接口方法可以看到,Servlet三个关键方法init()、service()、destroy(),其他两个方法:
一个是getServletConfig(),是获取ServletConfig对象,ServletConfig对象可以获取到Servlet的一些信息,包含ServletName、ServletContext、InitParameter、InitParameterNames等(WEB-INF目录下的web.xml中的servlet标签里面的信息)。其中ServletContext对象是servlet上下文对象,代表当前Web应用,并且它被所有客户端共享
另一个是getServletInfo(),是返回一个String类型的字符串,其中包括了关于Servlet的信息,例如作者、版本和版权。
GenericServlet实现了Servlet接口后,我们可以直接继承GenericServlet,就可以使用上面我们所介绍Servlet接口中的那几个方法了,能拿到ServletConfig,继而获取ServletContext,为了方便GenericServlet除了实现Servlet接口外,还实现了ServletConfig接口,就可以直接获取ServletContext了。
GenericServlet 中有两个init()方法原因:见Servlet详解之两个init方法的作用Service方法的执行
public abstract class GenericServlet implements Servlet, ServletConfig, java.io.Serializable { @Override public abstract void service(ServletRequest req, ServletResponse res) throws ServletException, IOException; }
查看GenericServlet的service()方法,它是一个抽象方法,实际上HttpServlet类继承了GenericServlet,它主要是实现service()方法的细节。
查看HttpServlet的代码public abstract class HttpServlet extends GenericServlet { 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; try { ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE); } catch (IllegalArgumentException iae) { // Invalid date header - proceed as if none was set ifModifiedSince = -1; } if (ifModifiedSince < (lastModified / 1000 * 1000)) { // 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); } } @Override public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { HttpServletRequest request; HttpServletResponse response; try { request = (HttpServletRequest) req; response = (HttpServletResponse) res; } catch (ClassCastException e) { throw new ServletException("non-HTTP request or response"); } service(request, response); } }
查看HttpServletRequest的代码
public interface HttpServletRequest extends ServletRequest
因此可以看到下边的
service(ServletRequest req, ServletResponse res)
方法主要是将ServletRequest
和ServletResponse
强制转换为了HttpServletRequest和HttpServletResponse,再调用service(HttpServletRequest req, HttpServletResponse resp)
方法,这个方法就是判断浏览器过来的请求方式是get还是post然后分别执行doGet()或doPost()方法,我们写的Servlet集成HttpServlet后,就只要重写doGet()和doPost()方法,而不用直接重写service()方法了,简便了开发。