分析servlet最深层的源码读懂servlet如何实现
目录
1 Servlet 继承结构
1.1Servlet 接口
反编译工具打开看其源码解析:
代码:
package javax.servlet;
import java.io.IOException;
public abstract interface Servlet
{
public abstract void init(ServletConfig paramServletConfig)
throws ServletException;
public abstract ServletConfig getServletConfig();
public abstract void service(ServletRequest paramServletRequest, ServletResponse paramServletResponse)
throws ServletException, IOException;
public abstract String getServletInfo();
public abstract void destroy();
}
1.init(),创建 Servlet 对象后立即调用该方法完成其他初始化工作。
2.service(),处理客户端请求,执行业务操作,利用响应对象响应客户端请求。
3.destroy(),在销毁 Servlet 对象之前调用该方法,释放资源。
4.getServletConfig(),ServletConfig 是容器向 servlet 传递参数的载体。
5.getServletInfo(),获取 servlet 相关信息。
1.2 ServletConfig 接口
package javax.servlet;
import java.util.Enumeration;
public abstract interface ServletConfig
{
public abstract String getServletName();
public abstract ServletContext getServletContext();
public abstract String getInitParameter(String paramString);
public abstract Enumeration<String> getInitParameterNames();
}
Servlet 运行期间,需要一些辅助信息,这些信息可以在 web.xml 文件中,使用一个或多 个元素,进行配置。当 Tomcat 初始化一个 Servlet 时,会将该 Servlet 的配置信息,封装到一个 ServletConfig 对象中,通过调用 init(ServletConfig config)方法,将 ServletConfig 对称传递给 Servlet
1.3 GenericServlet 是个抽象类
代码:
package javax.servlet;
import java.io.IOException;
import java.io.Serializable;
import java.util.Enumeration;
public abstract class GenericServlet
implements Servlet, ServletConfig, Serializable
{
private static final long serialVersionUID = 1L;
private transient ServletConfig config;
public void destroy()
{
}
public String getInitParameter(String name)
{
return getServletConfig().getInitParameter(name);
}
public Enumeration<String> getInitParameterNames()
{
return getServletConfig().getInitParameterNames();
}
public ServletConfig getServletConfig()
{
return this.config;
}
public ServletContext getServletContext()
{
return getServletConfig().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()
{
return this.config.getServletName();
}
}
GenericServlet 是实现了 Servlet 接口的抽象类。在 GenericServlet 中进一步的定义了Servlet 接口的具体实现,其设计的目的是为了和应用层协议解耦,在 GenericServlet 中包含一个 Service 抽象方法。我们也可以通过继承 GenericServlet 并实现 Service 方法实现请求的处 理 , 但是需要将 ServletReuqest 和 ServletResponse 转为 HttpServletRequest 和HttpServletResponse。
有的人会问有什么用呢?
我HttpServlet直接实现上面三个接口不香吗?现在Http协议较为优秀但是我以后再来一个XXX协议,再来跟多XXX协议,你的代码就会非常的冗余而且很多无用代码,而采用中间接口以后不管什么协议直接继承就可以了。
1.4 HttpServlet类
可以看到一个service父类和子类的方法同名:
也就是我们在写的时候会自动的转为子接口类型HttpServletRequest和Response因为他重写了GenericServlet,这个调用不是递归调用你看参数是不同的。
继承自 GenericServlet. 针对于处理 HTTP 协议的请求所定制。在 HttpServlet 的 service() 方法中已经把 ServletReuqest 和 ServletResponse 转 为 HttpServletRequest 和 HttpServletResponse。 直接使用 HttpServletRequest 和 HttpServletResponse, 不再需要强转。实际开发中, 直接继承 HttpServlet, 并根据请求方式复写 doXxx() 方法即可。