最近感觉到用久了SpringMVC、Struts2等框架,反而对它们的底层实现,即Servlet,的相关知识有了许多遗忘。现在参考了网上的一些博客,来进行一次知识点总结。
Servlet响应客户端请求的过程
Servlet生命周期
- init方法:当Servlet容器第一次加载并创建Servlet实例时,在调用该Servlet的构造函数后立即调用init方法对该Servlet对象进行初始化。构造器和init方法都只会被调用一次,这说明Servlet是单实例的(需要考虑线程安全的问题,不推荐在其中写全局变量)。
- service方法:每次请求都会调用service方法,它是实际用于响应请求的方法,可以被多次调用。
- destroy方法:在服务器端停止且卸载Servlet时执行该方法,用于释放当前Servlet所占用的资源,只会被调用一次。
以上方法都由Servlet容器(例如Tomcat)负责调用。
ServletConfig
Servlet接口的init方法会接收一个ServletConfig对象作为参数,即init(ServletConfig servletConfig),ServletConfig对象封装了该Serlvet的配置信息,并且可以获取ServletContext对象。例如:
在web.xml中配置Servlet的初始化参数:
可以在HelloServlet的init方法中获取这些参数的信息(在实际开发中,通常使用的Servlet都继承了HttpServlet类,可以通过getServletConfig()在该Servlet对象中获取到ServletConfig对象,不一定只能在init方法中使用,下面的getServletContext()也是一样):
当有请求发送到该Servlet后可以在控制台看到输出:
ServletContext
ServletContext对象代表着当前的WEB应用。可以认为SerlvetContext是当前 WEB应用的一个大管家,可以从中获取到当前WEB应用的各个方面的信息。
ServletContext对象可以由SerlvetConfig获取:
ServletContext主要的作用有:
① 获取当前WEB应用的初始化参数:
在web.xml中配置当前WEB应用的初始化参数:(这些参数可以被所有的 Servlet通过ServletContext获取,而上面配置在Servlet中的参数只能由对应的Servlet获取)
在init方法中获取到这些参数:
当有请求发送到该Servlet后可以在控制台看到输出:
② 获取当前WEB应用的某一个文件在服务器上的绝对路径,而不是部署前的路径。
例如现在在根目录下新建一个note.txt:
在Servlet中获取:
获取请求后在控制台输出:
realPath is G:\Eclipse\J2EE\workspace.metadata.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\JavaWeb\note.txt
③ 获取当前 WEB应用的名称:
④ 获取当前 WEB应用的某一个文件对应的输入流:
在src目录下新建一个jdbc.properties:
在Servlet中获取该文件的输入流:
输出:
注意区别另一种方法,即通过getClassLoader获取,这种方法的路径是没有/WEB-INF/classes/前缀的:
⑤ 和attribute相关的几个方法。
GenericServlet
GenericServlet是Servlet接口和ServletConfig接口的实现类,是一个抽象类,因为其中的service()方法为抽象方法。它的作用是:如果新建的 Servlet程序直接继承GenericSerlvet会使开发更简洁。
具体实现:
① 在GenericServlet中声明了一个SerlvetConfig类型的成员变量,在init(ServletConfig)方法中对其进行了初始化。
② 利用servletConfig成员变量的方法实现了 ServletConfig接口的方法。
③ 还定义了一个 init()方法,在init(SerlvetConfig)方法中对其进行调用,子类可以直接覆盖init()在其中实现对Servlet的初始化。
④ 不建议直接覆盖 init(ServletConfig),因为如果忘记编写super.init(config),而还是用了SerlvetConfig接口的方法,则会出现空指针异常。
⑤ 新建的 init(){}并非Serlvet的生命周期方法,而init(ServletConfig)是生命周期相关的方法。
以下是源码:
HttpServlet
HttpServlet是一个继承自 GenericServlet的Servlet,而且它是针对于 HTTP协议所定制。
HttpServlet在service(ServletRequest,ServletResponse)方法中直接把ServletReuqest和 ServletResponse强制转换为HttpServletRequest和HttpServletResponse。并调用了重载的service(HttpServletRequest, HttpServletResponse)方法。
在service(HttpServletRequest, HttpServletResponse)中,通过request.getMethod()获取请求方式,并根据请求方式创建了doXxx()方法(xxx为具体的请求方式,比如 doGet,doPost)。
实际开发中, 我们通常直接继承HttpServlet,这样做的好处是可以直接有针对性的覆盖doXxx()方法;直接使用HttpServletRequest和HttpServletResponse,而不再需要进行类型的强制转换。
主要源码如下: