Servlet处理请求的学习笔记

         我想如果咱想做一个还可以( 优  秀)的程序员,听老猿的话也是可以成长中必不可少的呐,下面是老猿的碎碎念:

1、你呀在平常的工作中知道自己的项目到底是做什么的,有哪些功能

2、你呀要明确项目的整体架构,能够清晰的指出从哪里调用到哪里,使用什么方法调用

3、你呀要明确模块在整个项目中所处于的位置及其作用

4、你呀要明确模块用到的哪些技术,了解整个项目用到了哪些技术

所以要搞清楚项目的流程,那得从出发点开始了解,我们就先拿Servlet来学习,人家Servlet毕竟是客户端和服务器端的中间层,值得研究。

一、Servlet 的生命周期

万物不离宗,我们经常实现的HttpServlet的源头是Servlet,那么我们就来看看

如上图,Servlet要经过init(初始化)-->service(服务的相应请求)-->destroy(销毁)这三个过程。

1、init()方法

init()方法是在服务器创建一个servlet实例的时候被调用的,只被调用一次。在服务器启动的时候,装载servlet,init()方法用于实例化servlet对象。我们有时候会在servlet层的web.xml配置当服务启动的时候需要做什么时候,例如配置编码,跨域,开始打印日志,执行监控等等。

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
		 xmlns="http://java.sun.com/xml/ns/javaee" xmlns:jsp="http://java.sun.com/xml/ns/javaee/jsp"
		 xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
		 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
		 id="WebApp_ID" version="3.0">

	<!-- 编码filter -->
	<filter>
		<filter-name>setCharacterEncodingFilter</filter-name>
		<filter-class>org.apache.catalina.filters.SetCharacterEncodingFilter</filter-class>
		<init-param>
			<param-name>encoding</param-name>
			<param-value>UTF-8</param-value>
		</init-param>
	</filter>
	<filter-mapping>
		<filter-name>setCharacterEncodingFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
	<!-- 编码filter -->

	<!-- 跨域访问 -->
	<filter>
		<filter-name>CORS</filter-name>
		<filter-class>com.thetransactioncompany.cors.CORSFilter</filter-class>
		<init-param>
			<param-name>cors.allowOrigin</param-name>
			<param-value>*</param-value>
		</init-param>
		<init-param>
			<param-name>cors.supportedMethods</param-name>
			<param-value>GET, POST, HEAD, PUT, DELETE</param-value>
		</init-param>
		<init-param>
			<param-name>cors.supportedHeaders</param-name>
			<param-value>Accept, Origin,
				X-Requested-With, Content-Type,Last-Modified,Authorization
			</param-value>
		</init-param>
		<init-param>
			<param-name>cors.exposedHeaders</param-name>
			<param-value>Set-Cookie</param-value>
		</init-param>
		<init-param>
			<param-name>cors.supportsCredentials</param-name>
			<param-value>true</param-value>
		</init-param>
	</filter>
	<filter-mapping>
		<filter-name>CORS</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
	<!-- 跨域访问 -->

	<!-- log4j初始 -->
	<servlet>
		<servlet-name>Log4jInit</servlet-name>
		<servlet-class>com.test.log.Log4jInit</servlet-class>
		<load-on-startup>0</load-on-startup>
	</servlet>
	<!-- log4j初始 -->

	<!-- 日志filter -->
	<filter>
		<filter-name>NdcFilter</filter-name>
		<filter-class>com.test.log.Log4jNdcFilter</filter-class>
	</filter>
	<filter-mapping>
		<filter-name>NdcFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
	<!-- 日志filter -->
</web-app>
     //或者是在servlet启动的时候初始化消费者等
    @Override
    public void init(ServletConfig config) throws ServletException {
        try {
            producer = initMQProducer();
        } catch (MQClientException e) {
            logger.error(e.getMessage(), e);
        }
    }

2、service()

service()是负责响应客户的请求,就如HttpServlet里面的service是不再需要子类去实现这个方法,传递给这个方法一个“请求”(ServletRequest)对象和一个“响应”(ServletResponse)对象作为参数。接收到客户端发出的请求对象,根据对象传来的req对象判断请求的方式,拿GET方法来说,接着会调用对应的doGet方法

扫描二维码关注公众号,回复: 5388111 查看本文章

doGet()方法如下:

 protected void doGet(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException
    {
        String protocol = req.getProtocol();
        String msg = lStrings.getString("http.method_get_not_supported");
        if (protocol.endsWith("1.1")) {
            resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
        } else {
            resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
        }
    }

覆盖此方法以支持GET请求也会自动支持HTTP HEAD请求。HEAD请求是一个GET请求,它在响应中不返回正文,只返回请求头字段。读取请求数据、写入响应头、获取响应的写入器或输出流对象,最后写入响应。最好包括内容类型和编码。当使用PrintWriter对象返回响应时,在访问对象之前设置内容类型。因为HTTP的Head是比response body先发送,所以在写请求的时要让servlet先包含headers。当使用HTTP 1.1分块编码(这意味着响应具有一个传输编码头)时,不要设置内容长度头。

在Servlet接口和GenericServlet中是没有doGet()、doPost()等这些方法的,HttpServlet中定义了这些方法,但都是返回error信息,所以,我们每次定义一个Servlet的时候,都必须实现doGet或doPost等这些方法。

3、destroy()

这个方法只在servlet退出服务的时候调用一次,servlet里面的所有“service()”会退出,或者超时请求。调用destroy()方法后是不会再调用“service()”方法的。该方法会给servlet一次清除资源的机会,清理所有被保存的资源(例如,内存、文件句柄、线程),并确保任何持久状态都与servlet在内存中的当前状态同步。

    @Override
    public void destroy() {
        if (Utils.isNotNull(producer)) {
            producer.shutdown();
        }
    }

以上就是servlet的生命周期。

二、Client 与Servlet之间的YY关系

如上图所示,简洁明了说的明明白白的

  1. Web Client发送一个请求到ServletComtainer(Tomcat)
  2. ServletContainer接收到请求
  3. ServletContainer先创建一个HTTPServletRequest,将Web Client请求的信息封装到这个对象中
  4. ServletContainer然后创建一个HTTPServletResponse
  5. ServletContainer接着会调用Servlet的“service()”方法,把HttpRequest对象与HttpResponse对象作为参数传给HttpServlet 对象,处理逻辑和数据
  6. HttpServlet调用HttpServletRequest对象的有关方法,获取Http请求信息
  7. HttpServlet调用HttpServletResponse对象的有关方法,生成响应数据。
  8. ServletContainer把HttpServlet的响应结果传给Web Client。

三、创建servlet这个对象的时机

Servlet对象如何配置?实际上是通过读取web.xml配置文件来实现的。先知道怎么配置,然后了解其创建的时机。

正如上的配置文件所示,有<servlet>的节点开始:

    <servlet>
        <servlet-name>Init</servlet-name>
        <servlet-class>org.xl.servlet.InitServlet</servlet-class>
        <!--选择性的配置初始化参数-->
        <init-param>
        <param-name>config</param-name>
        <param-value>/WEB-INF/struts-config.xml</param-value>
        </init-param>

        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>getList</servlet-name>
        <url-pattern>/getList</url-pattern>
    </servlet-mapping>


    <!--
    <load-on-startup>1</load-on-startup>节点的说明
    如果没有设置loadOnStartup,则第一次请求的时候实例化

    分三种情况:
    loadOnStartup < 0 
    即负数的情况下,web容器启动的时候不做实例化处理,servlet首次被调用时做实例化
    这种情况和没有设置loadOnStartup是一样的。
    loadOnStartup > 0
    web容器启动的时候做实例化处理,顺序是由小到大,正整数小的先被实例化
    loadOnStartup = 0
    web容器启动的时候做实例化处理,相当于是最大整数,因此web容器启动时,最后被实例化
    -->
  1.     当Servlet容器启动的时候读取<servlet>配置节信息,
  2.     根据<servlet-class>配置节信息创建Servlet对象,
  3.     同时根据<init-param>配置节信息创建HttpServletConfig对象,
  4.     然后执行Servlet对象的init方法,
  5.     并且根据<load-on-startup>配置节信息来决定创建Servlet对象的顺序,
  6.     如果此配置节信息为负数或者没有配置,那么在Servlet容器启动时,将不加载此Servlet对象。
  7.     当客户访问Servlet容器时,Servlet容器根据客户访问的URL地址,
  8.     通过<servlet-mapping>配置节中的<url-pattern>配置节信息找到指定的Servlet对象,
  9.     并调用此Servlet对象的service方法。

接着来看看时机是否成熟:

最好的时机就是你需要servlet为你做什么事情,ServletContainer启动的时候会读取web.xml配置文件中的信息,构建指定的Servlet对象,创建ServletConfig对象,同时将ServletConfig对象作为参数来调用Servlet对象的init方法。

而Servlet容器启动后,servlet对象的创建随着客户端的请求来的,ServletContainer会判断内存中是否存在指定的Servlet对象,如果没有则创建它,根据客户的请求创建HttpRequest、HttpResponse对象,从而调用Servlet 对象的service方法。在你需要的时候去创建和设置创建的优先级更好的为己所用。

servlet对象被销毁的时候需要程序退出的做些什么也是由你来决定的。

猜你喜欢

转载自blog.csdn.net/LCF_lxf_ldy/article/details/86014722