Web核心-Servlet
Servlet实际上是ServerApplet--小服务程序或服务连接器,用Java编写的服务器端程序,主要功能在于交互式地浏览和修改数据,生成动态Web内容。与常用的协议,如DNS,TCP/IP,HTTP类似,Servlet是作为一整套规范存在的;同时作为J2EE标准的一部分,定义了javaweb开发的标准。Servlet制定了java处理WEB请求的一系列标准,我们只需要按照标准规定的去做就可以了。
实际上,无论是Struts2的FilterDispatcher还是SpringMvc的DispatcherServlet,其底层都是通过实现Sevlet或者Servlet类型的扩展【如:GenericServlet】来实现的。
1.Servlet接口
下图为Servlet3.1中的结构图:
<figure style="font-size: inherit; color: inherit; line-height: inherit; margin: 0px; padding: 0px;"> image<figcaption style="line-height: inherit; margin: 0px; padding: 0px; margin-top: 10px; text-align: center; color: rgb(153, 153, 153); font-size: 0.7em;"></figcaption>
</figure>
因为Servlet是以规范的方式存在的,实际上就是定义一系列规范接口。在Servlet接口中,主要包括以下几个接口:
<figure style="font-size: inherit; color: inherit; line-height: inherit; margin: 0px; padding: 0px;"> image<figcaption style="line-height: inherit; margin: 0px; padding: 0px; margin-top: 10px; text-align: center; color: rgb(153, 153, 153); font-size: 0.7em;"></figcaption>
</figure>
- 1)init方法是在容器启动时被容器调用,且只会被调用一次;
- 2)getServletConfig方法用于获取ServletConfig;
- 3)service方法用于处理一个具体的请求
- 4)getServletInfo方法用于获取Servlet相关的信息:版权等。
- 5)destroy方法用来销毁一个Servlet,和init一样,只会被调用一次,一般在服务器关闭时用于释放一些资源。
init方法调用时会接受一个ServletConfig类型的参数,用于初始化Servlet,由容器传入。ServletConfig,顾名思义,其包含了Serlvet的配置信息。通常情况下,我们在web.xml文件中定义Serlvet时,会通过init-param标签来进行参数配置。在Springmvc的配置中,通常通过以下方式来配置参数:
<figure style="font-size: inherit; color: inherit; line-height: inherit; margin: 0px; padding: 0px;"> image<figcaption style="line-height: inherit; margin: 0px; padding: 0px; margin-top: 10px; text-align: center; color: rgb(153, 153, 153); font-size: 0.7em;"></figcaption>
</figure>
2.ServletConfig接口
<figure style="font-size: inherit; color: inherit; line-height: inherit; margin: 0px; padding: 0px;"> image<figcaption style="line-height: inherit; margin: 0px; padding: 0px; margin-top: 10px; text-align: center; color: rgb(153, 153, 153); font-size: 0.7em;"></figcaption>
</figure>
1)getServletName用于获取Servlet的名字,也就是我们在web.xml中定义的servlet-name
2)getServletContext返回ServletContext,代表我们当前应用本身
3)getInitParameter用于获取init-param配置的参数
4)getInitParameterNames用于获取所有init-param配置名字的集合
ServletContext和ServletConfig最常见的使用就是传递初始化参数。来看下spring中的contextConfigServlet的参数配置
<figcaption style="line-height: inherit; margin: 0px; padding: 0px; margin-top: 10px; text-align: center; color: rgb(153, 153, 153); font-size: 0.7em;"></figcaption>
</figure>
通过context-param配置的contextConfigLocation配置到了ServletContext中,再通过Servlet下的init-param配置的contextConfigLocation配置到ServletConfig中,在Servlet中可以通过getInitParameter方法获取具体的信息。
3.GenericServlet
GenericServlet是Servlet的默认实现,代码如下:
package javax.servlet;import java.io.IOException;import java.io.Serializable;import java.util.Enumeration;import java.util.ResourceBundle;public abstract class GenericServlet implements Servlet, ServletConfig, Serializable{ private static final String LSTRING_FILE = "javax.servlet.LocalStrings"; private static ResourceBundle lStrings = ResourceBundle.getBundle("javax.servlet.LocalStrings"); private transient ServletConfig config; public void destroy() { } public String getInitParameter(String name) { ServletConfig sc = getServletConfig(); if (sc == null) { throw new IllegalStateException(lStrings.getString("err.servlet_config_not_initialized")); } return sc.getInitParameter(name); } public Enumeration getInitParameterNames() { ServletConfig sc = getServletConfig(); if (sc == null) { throw new IllegalStateException(lStrings.getString("err.servlet_config_not_initialized")); } return sc.getInitParameterNames(); } public ServletConfig getServletConfig() { return this.config; } public ServletContext getServletContext() { ServletConfig sc = getServletConfig(); if (sc == null) { throw new IllegalStateException(lStrings.getString("err.servlet_config_not_initialized")); } return sc.getServletContext(); } public String getServletInfo() { return ""; } public void init(ServletConfig config) throws ServletException { this.config = config; init(); } public void init() throws ServletException { } public void log(String msg) { getServletContext().log(getServletName() + ": " + msg); } public void log(String message, Throwable t) { getServletContext().log(getServletName() + ": " + message, t); } public abstract void service(ServletRequest paramServletRequest, ServletResponse paramServletResponse) throws ServletException, IOException; public String getServletName() { ServletConfig sc = getServletConfig(); if (sc == null) { throw new IllegalStateException(lStrings.getString("err.servlet_config_not_initialized")); } return sc.getServletName(); }}
从其继承和实现关系来看,GenericServlet主要做了3件事:
1.实现了ServletConfig接口,这样我们就可以直接调用ServletConfig里面的方法;
GenericServlet实现了ServletConfig,可以在需要的时候直接调用ServletConfig中的方法,不需要再先获取ServletConfig对象;比如,获取ServletContext的时候可以直接调用getServletContext,而无需调用getServletConfig().getServletContext(),但是实际上,其底层的内部实现还是在内部还是进行了getServletConfig().getServletContext()的调用。
<figcaption style="line-height: inherit; margin: 0px; padding: 0px; margin-top: 10px; text-align: center; color: rgb(153, 153, 153); font-size: 0.7em;"></figcaption>
</figure>
2.提供了无参的init方法
GenericServlet实现了Servlet的init(ServletConfig config)方法,在里面将config设置给了其内部变量config,然后调用了无参的init方法;此方法可以在子类中通过覆盖它来完成初始化工作。
<figcaption style="line-height: inherit; margin: 0px; padding: 0px; margin-top: 10px; text-align: center; color: rgb(153, 153, 153); font-size: 0.7em;"></figcaption>
</figure>
这种方式具有的有点包括以下几点:
a.config设置为内部属性,这样可以在ServletConfig的接口方法中直接调用Config的相应方法来执行;
b.我们在写Serlvet的时候可以不用再关心Config,只需要执行自己的初始化逻辑即可
c.在重写init方法时,不需要再调用super.init(config)。
3.提供了Log方法
GenericServlet提供了2个log方法,一个用于记录日志,一个用于记录异常。其具体的实现是通过传给ServletConfig的日志实现的。
GenericServlet是与具体协议无关的。
4.HttpServlet
HttpServlet是基于Http协议实现的Servlet的基类,写Servlet时直接继承HttpServlet即可,不需要再重头实现Servlet接口,SpringMvc中的dispatcherServlet就是HttpServlet的子类。 HttpServlet是与Http协议相关的,HttpServlet处理请求主要是通过重写父类的service方法来完成具体的请求处理的。在service方法中首先是将ServletRequest和ServletResponse转换成HttpServletRequest和HttpServletResponse,然后根据请求的不同路由到不同的处理过程中去【处理方法就是我们常见的doXXX的方法。最常见的就是doGet和doPost】
<figure style="font-size: inherit; color: inherit; line-height: inherit; margin: 0px; padding: 0px;"> image<figcaption style="line-height: inherit; margin: 0px; padding: 0px; margin-top: 10px; text-align: center; color: rgb(153, 153, 153); font-size: 0.7em;"></figcaption>
</figure>