Servlet
1.1 Servlet整体结构
图解可以看到SevletConfig和Servlet都是顶层接口类,而GenericServlet实现了这两个顶层类,然后HttpServlet实现了GenericServlet类,所以要实现一个Servlet直接就可以继承HttpServlet1.2 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();
}
复制代码
依次解析这五个方法
- init()方法接收一个ServletConfig参数,由容器传入,ServletConfig就是Servlet的配置,在web.xml中定义Servlet时通过init-param标签配置的参数由ServletConfig保存
- init()方法Servlet创建时执行,且只会被调用一次
- getServletConfig()方法获取Servlet配置
- service()处理具体请求
- getServletInfo()获取Servlet的相关信息
- destroy()销毁对象,服务器关闭时执行
总结
init(ServletConfig config)这个参数是ServletConfig类型的
ServletConfig这个接口的方法都可以使用
所以能用这个引用参数下的方法
getInitParameterNames()获取init-param标签下的键值对
getServletName()获取servlet-name里自定义的值
getServletContext()获取context-param标签下的东西
复制代码
1.3 ServletConfig接口
源码如下
public interface ServletConfig {
//用于获取Servlet名,web.xml中定义的servlet-name
public String getServletName();
//获取应用本身(非常重要)
public ServletContext getServletContext();
//获取init-param中的配置参数
public String getInitParameter(String name);
//获取配置的所有init-param名字集合
public Enumeration getInitParameterNames();
}
复制代码
ServletConfig接口下可获取web.xml的参数
首先看下web.xml配置
Servlet1
com.breeze.servlet.Servlet1
a
96
b
97
Servlet1
/servlet
复制代码
接下来获取这些参数
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("ServletName-----------------------");
String name=getServletName();
System.out.println(name);
System.out.println("第一种方式获得init-param--------------");
//通过键获得值
String initParameter = getInitParameter("a");
System.out.println(initParameter);
System.out.println("第二种方式获得init-param---------------");
Enumeration parameterNames =getInitParameterNames();
while(parameterNames.hasMoreElements()) {
String key = parameterNames.nextElement();
String value = getInitParameter(key);
System.out.println(key+"----"+value);
}
}
复制代码
1.4 GenericServlet抽象类
GenericServlet是Servlet的默认实现,与具体协议无关的
GenericServlet主要做了三件事
1,实现了ServletConfig的接口,可以调用ServletConfig里面的方法,不需要获取getServletConfig对象。获取ServletContext可以直接调用getServletContext,不用getServletConfig().getServletContext()
用init()把ServletConfig变成内部变量引用,然后重写ServletConfig接口的所有方法,用这个变量调用
public ServletContext getServletContext() {
return getServletConfig().getServletContext();
}
但是我们可以看到追根溯源getServletContext()还是由getServletConfig()调用的
public ServletConfig getServletConfig() {
return config;
}
getServletConfig()方法返回了config,config是从init()方法拿到的ServletConfig
复制代码
2,提供了无参init()方法,
public void init() throws ServletException {}
public void init(ServletConfig config) throws ServletException {
this.config = config;
this.init();
}
复制代码
3,提供了两个log()方法,一个记录日志,一个记录异常,其具体实现是通过传给ServletConfig的日志实现的
public void log(String msg) {
getServletContext().log(getServletName() + ": " + msg);
}
public void log(String message, Throwable t) {
getServletContext().log(getServletName() + ": " + message, t);
}
复制代码
GenericServlet源码总结
tomcat会执行init()有参方法
init()有参方法
参数是web.xml,也就是ServletConfig,把ServletConfig这个参数指向内部变量config
然后调用了init()无参方法
init()无参方法是空的,方便你自己实现类去重写初始化
GenericServlet重写了接口ServletConfig的所有方法,用config这个内部变量调用
所以我们在实现类就不用去关心config,只需要执行自己的逻辑即可
在重写init()方法时,也不需要调用super.init(config)
所以在实现类去调用ServletConfig的方法时,可以直接写接口类的方法即可,因为GenericServlet重写了
比如用getInitParameterNames()
不需要在实现类去定义ServletConfig,也不用去this.getServletConfig().getInitParameterNames();
可以直接getInitParameterNames()
复制代码
1.5 HttpServlet类
HttpSerVlet是基于Http协议实现的Servlet基类,我们刚开始写Servlet的时候是实现Servlet接口,后面在写Servlet的时候直接继承HttpServlet类就可以了
HttpServlet处理请求主要是通过重写父类的service()来完成具体请求的,在第一个service里是把ServletRequest和ServletResponse强转成HttpServletRequest和HttpServletResponse,然后调用第二个service()方法
第二个service则根据http不同的请求,调用相应的方法处理,如doGet,doPost,所以我们代码也可以写在doGet,doPost里
在html界面中,要是没有设定提交的方法,servlet默认以doGet的方法进行处理。
执行流程
客户端发送请求,通过web.xml的url匹配跳转到到实现类servlet
而实现类继承HttpServlet,所以先说父类
HttpServlet执行service接受请求进行强转,调用第二个service判断时什么方式请求
如判断的时doGet请求,则执行doGet方法
但我们重写了doGet方法,所以将请求发送到了我们重写的doGet方法中
如果我们重写的不是doGet而是service则一样,因覆盖了父类的service则将请求发送到我们重写的sercvice
复制代码
复制代码