• SERVLET 高效总结


     一、Servlet简介

          Servlet是JavaWeb或者JavaEE基础、学会了servlet, 你就入了Javaweb开发的门。Servlet是sun公司提供的一门用于开发动态web资源的技术。Sun公司提供了一套标准的ServletAPI, Servlet开发有二个步骤(1)书写servlet代码 (2) 部署到应用服务器上(Tomcat等)。同样servlet使用Java语言、具有Java语言的优点,如夸平台。

          在文章之前推荐一本工具书--《head first jsp&Servlet》, 该书不仅讲述了JSP和SERVLET的基础内容, 吸引人的是他还讲述TOMCAT如何作为"应用服务器"和"SERVLET容器"。

     二、Servlet开发

         Servlet接口SUN公司定义了两个默认实现类,分别为:GenericServlet、HttpServlet

            HttpServlet指能够处理HTTP请求的servlet,它在原有Servlet接口上添加了一些与HTTP协议处理方法,它比Servlet接口的功能更为强大。因此开发人员在编写Servlet时,通常应继承这个类,而避免直接去实现Servlet接口。

       HttpServlet在实现Servlet接口时,覆写了service方法,该方法体内的代码会自动判断用户的请求方式,如为GET请求,则调用HttpServlet的doGet方法,如为Post请求,则调用doPost方法。因此,开发人员在编写Servlet时,通常只需要覆写doGet或doPost方法,而不要去覆写service方法。

         GenericServlet业务方法为service、不仅仅可以处理HTTP请求、还可以处理其他请求, 但是javaweb是浏览器开发,使用的基本上是HTTP请求,所以绝大多数情况下我们应该继承HttpServlet。

        项目创建是web-project, 在创建servlet应该选择Servlet选项(自动填写web.xml信息), 默认路径会带上/servlet,在创建servlet是next可以选择你想要的路径。GenericServletDemo 中ServletRequest是HTTPServletRequest父类。

    public class GenericServletDemo extends GenericServlet {
        
        private Book book;
        @Override
        public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
              //getParameter->获取request域的参数
                    String bookname=req.getParameter("bookname");
                    Double price=Double.parseDouble(req.getParameter("price"));
                    book=new Book(bookname, price);                
                    //调用service业务层
                    //调用Dao,可以使用原生的JDBC或者使用DBUtil工具保存数据
                    //这里演示就打印数据
                    System.out.println(book);
                    //跳转页面,GenericServlet怎么实现跳转
                    HttpServletRequest request=(HttpServletRequest)req;
                    request.getRequestDispatcher("index.jsp").forward(req, res);
                    
        }
    class HttpServletDemo extends HttpServlet {
        public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
         //假设Post和Get处理方式一直
            
        }
        public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
           //控制层操作
        }
    
    }
    <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">
    <web-app>
      <servlet>
        <servlet-name>GenericServletTest</servlet-name>
        <servlet-class>it.servlet.GenericServletTest</servlet-class>
      </servlet>
      <servlet>
        <servlet-name>HttpServletDemo</servlet-name>
        <servlet-class>it.servlet.HttpServletDemo</servlet-class>
      </servlet>
    
      <servlet-mapping>
        <servlet-name>GenericServletTest</servlet-name>
        <url-pattern>/GenericServletTest</url-pattern>
      </servlet-mapping>
      <servlet-mapping>
        <servlet-name>HttpServletDemo</servlet-name>
        <url-pattern>/HttpServletDemo</url-pattern>
      </servlet-mapping>
    
    </web-app>

     

    三、Servlet与Java对象

            Servlet是一个供其他Java程序(Servlet引擎)调用的Java类,它不能独立运行,它的运行完全由Servlet引擎(容器)来控制和调度。
      针对客户端的多次Servlet请求,通常情况下,服务器只会创建一个Servlet实例对象,也就是说Servlet实例对象一旦创建,它就会驻留在内存中,为后续的其它请求服务,直至web容器退出,servlet实例对象才会销毁。

    四、Servlet的生命周期

        应用服务器启动之后, Servlet不会马上被创建(优化原则),当第一次Http请求时,web服务器收到客户端的Servlet访问请求后:
       ①Web服务器首先检查是否已经装载并创建了该Servlet的实例对象。如果是,则直接执行第④步,否则,执行第②步。
       ②装载并创建该Servlet的一个实例对象。
      ③调用Servlet实例对象的init()方法。
      ④创建一个用于封装HTTP请求消息的HttpServletRequest对象和一个代表HTTP响应消息的HttpServletResponse对象,然后调用Servlet的service()方法并将请求和响应对象作为参数传递进去。
      ⑤WEB应用程序被停止或重新启动之前,Servlet引擎将卸载Servlet,并在卸载之前调用Servlet的destroy()方法。

       1、Servlet创建和init

         Servlet是单列模式, 也就是在第一次处理请求时创建,之后的请求不会再调用,除非重启服务器或者重新部署。Servlet创建之后调用init函数,也是只执行一次,用于Servlet初始化。也就是后面的请求不会创建Servlet,更不会在调用init初始化方法。

        2、service方法

         tomcat服务器封装HTTP请求消息的HttpServletRequest对象和一个代表HTTP响应消息的HttpServletResponse对象, 然后调用Servlet的service()方法来决定调用哪个具体的方法,时doPost,或者doGet,还是其他。

       3、doPost和doGet方法

        处理具体的请求。

       4、destroy() 方法

        destroy() 方法只会被调用一次,在 Servlet 生命周期结束时被调用。destroy() 方法可以让您的 Servlet 关闭数据库连接、停止后台线程、把 Cookie 列表或点击计数器写入到磁盘,并执行其他类似的清理活动。在调用 destroy() 方法之后,servlet 对象被标记为垃圾回收。

     

    五、Servlet如何初始化程序

         如果我们需要在处理请求之前做一些事情,比如创建数据库,表或者写入一些常量数据。Servlet的运行需要tomcat容器的创建的调度,如果在服务器启动的时候就马上创建一个InitServlet,调用init方法做些处理,就可以实现。这样的Servlet怎么写? 

         如果在<servlet>元素中配置了一个<load-on-startup>元素,那么WEB应用程序在启动时,就会装载并创建Servlet的实例对象、以及调用Servlet实例对象的init()方法。
         举例:

        <servlet>
            <servlet-name>invoker</servlet-name>
            <servlet-class>
                org.apache.catalina.servlets.InvokerServlet
            </servlet-class>
            <load-on-startup>1</load-on-startup> <!-- 1 数值表示优先创建, 比如2, 就会在该Servlet创建之后在创建-->
        </servlet>

     六、Servlet配置的杂事

        Servlet配置文件为根目录WEB-INFO子目录下的web.xml文件, 他长什么样子,如下。

    <!--
    <servlet>标签给<Servlet-class>提供一个签名<Servlet-name> 注意一个Servlet只能有一个名字,不同的Servlet,名称不一样。
    <servlet-mapping> //前端JSP请求配置内容、 意思是<url-pattern>路径下的请求由 <servlet-name>处理,在根据 <servlet-name>找到<Servlet>调用相对应的class。<servlet-mapping> 针对不用请求可以
    //使用同一个servlet-class来处理。

    -->
    <servlet> <servlet-name>HttpServletDemo</servlet-name> <servlet-class>it.servlet.HttpServletDemo</servlet-class> </servlet> <servlet-mapping> <servlet-name>HttpServletDemo</servlet-name> <url-pattern>/HttpServletDemo</url-pattern> </servlet-mapping>

     对于新手或者不注重细节的朋友来说,会发现有时web项目中居然看不见配置文件(看不见不代表没有)。而创建Servlet,是如下这样子的。

    解释一下:@WebServlet("/TestServlet")为访问路径注解,web.xml可以识别这种引用,和直接在web.xml配置是一样的道理。学过Spring的朋友,肯定非常容易理解。

    @WebServlet("/TestServlet")
    public class TestServlet extends HttpServlet {
        private static final long serialVersionUID = 1L;
      。。。
    }

       

     七、Servlet和JSP的区别

             jsp经编译后就变成了Servlet。JSP的本质就是Servlet,JVM只能识别java的类,不能识别JSP的代码,Web容器将JSP的代码编译成JVM能够识别的java类。Servlet中的内置对象

    都是必须通过HttpServletRequest对象,HttpServletResponse对象以及HttpServlet对象得到.Jsp是Servlet的一种简化,使用Jsp只需要完成程序员需要输出到客户端的内容,Jsp中

    的Java脚本如何镶嵌到一个类中,由Jsp容器完成。而Servlet则是个完整的Java类,这个类的Service方法用于生成对客户端的响应。

     八、如何书写线程安全的Servlet

          Servlet是单线程模式,如果存在共享的资源时,很可能会出现线程不安全的情况。Servlet线程安全是学习Servlet必须掌握的内容。不过话说回来,在以后的学习或者开发中,

    线程安全都是问题。如果是JavaEE初级开发者,多线程安全是难题之一。所以需要以后不断的总结和积累,这里简述初级的解决方案。

       1、Servlet单实例多线程机制

                 Servlet采用多线程来处理多个请求同时访问。servlet依赖于一个线程池来服务请求。线程池实际上是一系列的工作者线程集合。Servlet使用一个调度线程来管理工作者线程。 

               当容器收到一个Servlet请求,调度线程从线程池中选出一个工作者线程,将请求传递给该工作者线程,然后由该线程来执行Servlet的service方法。当这个线程正在执行的时候,容器收到另外一个请求,调度线程同样从线程池中选出另一个工作者线程来服务新的请求,容器并不关心这个请求是否访问的是同一个Servlet.当容器同时收到对同一个Servlet的多个请求的时候,那么这个Servlet的service()方法将在多线程中并发执行。 
                 Servlet容器默认采用单实例多线程的方式来处理请求,这样减少产生Servlet实例的开销,提升了对请求的响应时间,对于Tomcat可以在server.xml中通过<Connector>元素设置线程池中线程的数目。

       2、如何开发线程安全的Servlet程序

               (1)实现 SingleThreadModel 接口  

           SingleThreadModel是一个标志接口,对于实现了SingleThreadModel接口的Servlet,Servlet引擎仍然支持对该Servlet的多线程并发访问,其采用的方式是产生多个Servlet实例对象,并发的每个线程分别调用一个独立的Servlet实例对象。

           这种处理,Servlet变成多例模式,好处是不存在线程安全问题,缺点也比较明显,比如需要维护大量的Servlet对象,这种方案有没谁采取,答案是有的,Struts2就是多例模式。但是Servlet本身为单例模式,我们不应该随便修改它,以免造成不必要的麻烦。在极端的情况下,或许可以,在Servlet API 2.4中,已经将SingleThreadModel标记为Deprecated(过时的),连Servlet本身都否定这种方式。  

            (2)使用synchronized同步代码块

           这是针对多线程问题提出的解决方案。Servlet访问量高时,同步块会导致运行效率较低,服务器响应速度慢,这可能导致严重问题。和(1)一样,慎重使用。

          (3)避免使用实例变量 

          多线程问题是由于多个线程同时操作统一资源造成的,比如Servlet的实例变量(局部变量是不影响的)和读写同一个文件。问题是这么导致的,我们就应该在源头上尽量避免。再者Servlet中定义属性或者类属性本来就没必要性。

           综上可知, 解决Servlet线程安全相对比较简单,就是:慎用或者不用SingleThreadModel接口和synchronized代码块,不定义局部变量,源头上避免操作同一资源。单例模式简单易用,SpringMVC框架同样使用这种模式。

            

  • 相关阅读:
    poj 2417 Discrete Logging
    洛谷 P2886 [USACO07NOV]牛继电器Cow Relays
    bzoj 3232 圈地游戏——0/1分数规划(或网络流)
    bzoj 4753 [Jsoi2016]最佳团体——0/1分数规划
    bzoj 5281 [Usaco2018 Open]Talent Show——0/1分数规划
    CF 949D Curfew——贪心(思路!!!)
    bzoj 3872 [Poi2014]Ant colony——二分答案
    bzoj 1731 [Usaco2005 dec]Layout 排队布局——差分约束
    洛谷 1344 [USACO4.4]追查坏牛奶Pollutant Control——最大流
    洛谷 1262 间谍网络——缩点+拓扑
  • 原文地址:https://www.cnblogs.com/achievement-active/p/9320618.html
Copyright © 2020-2023  润新知