细说Servlet

一、如何开发一个Servlet

1、编写Java类,继承HttpServlet类为什么要继承这个HttpServlet类呢?所有的Servlet类都要实现Servlet接口,GenericServlet实现了Servlet接口,但是这个类没有具体协议,所以HttpServlet继承了GenericServlet类,因此我们在编写Servlet类的时候,我们只需继承HttpServlet类,覆盖里边我们要用到的方法就可以。)

2、重写doGET()和doPost方法

3、Servlet程序由tomcat服务器运行。

  3.1 Servlet程序的class码拷贝到WEB-INF下边的classes目录里

  3.2 在web.xml 文件中进行配置

部署web.xml文件

  由于客户端是通过URL地址访问web服务器中的资源,所以Servlet程序若想被外界访问,必须把servlet程序映射到一个URL地址上,这个工 作在web.xml文件中使用<servlet>元素和<servlet-mapping>元素完成。

<servelet>
        <!-- 给Servlet取名,可以任意取名 -->
        <servelet-name>Hello</servelet-name>
        <!-- 指明servlet的路径,就是servlet的包+类名 -->
        <servlet-class>com.lyjs.Hello</servlet-class>
</
servelet>

<
servelet-mapping> <!--  servlet的内部名称,一定要和上面的内部名称保持一致!! --> <servelet-name>Hello</servelet-name> <!-- 浏览器中输入的url,可以随意取名 -->
     
<url-pattern>/Hello</url-pattern>
</
servelet-mapping>

3.3一对多映射

同一个Servlet可以被映射到多个URL上,即多个<servlet-mapping>元素的<servlet-name>子元素的设置值可以是同一个Servlet的注册名。这样就可以通过不同的URL来访问同一个Servlet。

<!--Hello被映射到/Hello-->
<servelet-mapping>
        <servelet-name>Hello</servelet-name>
        <url-pattern>/Hello</url-pattern>
</servelet-mapping>


<!--Hello被映射到/My/Hello-->

<servelet-mapping>
        <servelet-name>Hello</servelet-name>
        <url-pattern>/My/Hello</url-pattern>
</servelet-mapping>


<!--所以可以通过两个URL,都可以访问到Hello这个Servlet-->

3.4、映射匹配问题:

                   url-pattern                   浏览器输入
精确匹配             /first                 http://localhost:8080/day10/first
                    /itcast/demo1          http://localhost:8080/day10/itcast/demo1

模糊匹配             
  
            /*   http://localhost:8080/day10/任意路径 /itcast/* http://localhost:8080/day10/itcast/任意路径 *.后缀名   http://localhost:8080/day10/任意路径.do *.do *.action *.html(伪静态)

注意:

  1. url-pattern要么以 / 开头,要么以 * 开头,例如:itlyjs 为非法路径。
  2. 在Servlet中模糊匹配有两种固定的形式:一种是"*.扩展名",另一种是以正斜杠(/)开头并以"/*"结尾。不能同时使用两种模糊匹配,要么/* ,要么 *.do. 例如 /itlyjs/*.do是非法路径。
  3. 当有输入的URL有多个Servlet同时匹配的时候:精确匹配优先,(长的最像的优先匹配,),以后缀名结尾的模糊url-pattern优先级最低

练兵场地

  1. Servlet1 映射到 /abc/*
  2. Servlet2 映射到 /*
  3. Servlet3 映射到 /abc
  4. Servlet4 映射到 *.do

问题:

  1. 当请求URL为“/abc/a.html”,“/abc/*”和“/*”都匹配,哪个servlet响应,Servlet引擎将调用Servlet1。
  2. 当请求URL为“/abc”时,“/abc/*”和“/abc”都匹配,哪个servlet响应,Servlet引擎将调用Servlet3
  3. 当请求URL为“/abc/a.do”时,“/abc/*”和“*.do”都匹配,哪个servlet响应,Servlet引擎将调用Servlet1
  4. 当请求URL为“/a.do”时,“/*”和“*.do”都匹配,哪个servlet响应, Servlet引擎将调用Servlet2。
  5. 当请求URL为“/xxx/yyy/a.do”时,“/*”和“*.do”都匹配,哪个servlet响应, Servlet引擎将调用Servlet2。

优先级:完全匹配>*匹配>后缀名匹配 

四、Servlet缺省路径

servlet的缺省路径(<url-pattern>/</url-pattern>)是在tomcat服务器内置的一个路径。该路径对应的是一个DefaultServlet(缺省Servlet)。这个缺省的Servlet的作用是用于解析web应用的静态资源文件。

问题: URL输入http://localhost:8080/day10/index.html 如何读取文件?

  1. 到当前day10应用下的web.xml文件查找是否有匹配的url-pattern
  2. 如果没有匹配的url-pattern,则交给tomcat的内置的DefaultServlet处理
  3. DefaultServlet程序到day10应用的根目录下查找是存在一个名称为index.html的静态文件。
  4. 如果找到该文件,则读取该文件内容,返回给浏览器。
  5. 如果找不到该文件,则返回404错误页面。

总结:web应用的资源分为两类,动态资源和静态资源。tomcat先找动态资源,再找静态资源

五、Servlet的生命周期

  1. 构造方法:创建Servlet对象的时候调用。默认情况下,第一次访问Servlet的时候创建Servlet对象,只调用1次。证明Servlet对象在tomcat是单例的。
  2. init方法:创建完Servlet对象的时候调用,只调用1次
  3. service方法:每次发出请求时调用1次。调用n次
  4. destory方法:销毁Servlet对象的时候调用,停止服务器或重新部署web应用时销毁Servlet对象,只调用1次。

文字描述:(可以跳过)

  Servlet是一个供其他Java程序(Servlet引擎)调用的Java类,它不能独立运行,它的运行完全由Servlet引擎来控制和调度。针对客户端的多次Servlet请求,通常情况下,服务器只会创建一个Servlet实例对象,也就是说Servlet实例对象一旦创建,它就会驻留在内存中,为后续的其它请求服务,直至web容器退出,servlet实例对象才会销毁。在Servlet的整个生命周期内,Servlet的init方法只被调用一次。而对一个Servlet的每次访问请求都导致Servlet引擎调 用一次servlet的service方法。对于每次访问请求,Servlet引擎都会创建一个新的HttpServletRequest请求对象和一个 新的HttpServletResponse响应对象,然后将这两个对象作为参数传递给它调用的Servlet的service()方法,service 方法再根据请求方式分别调用doXXX方法。

六、伪代码演示Servlet的生命周期

Tomtcat内部代码运行:
            1)通过映射找到到servlet-class的内容,字符串: gz.itcast.a_servlet.FirstServlet
            2)通过反射构造FirstServlet对象
                    2.1 得到字节码对象
                    Class clazz = class.forName("gz.itcast.a_servlet.FirstServlet");
                    2.2 调用无参数的构造方法来构造对象
                    Object obj = clazz.newInstance();     ---1.servlet的构造方法被调用
            3)创建ServletConfig对象,通过反射调用init方法
                    3.1 得到方法对象
                    Method m = clazz.getDeclareMethod("init",ServletConfig.class);
                    3.2 调用方法
                    m.invoke(obj,config);             --2.servlet的init方法被调用
            4)创建request,response对象,通过反射调用service方法
                    4.1 得到方法对象
                    Methodm m =clazz.getDeclareMethod("service",HttpServletRequest.class,HttpServletResponse.class);
                    4.2 调用方法
                    m.invoke(obj,request,response);  --3.servlet的service方法被调用
            5)当tomcat服务器停止或web应用重新部署,通过反射调用destroy方法
                    5.1 得到方法对象
                    Method m = clazz.getDeclareMethod("destroy",null);
                    5.2 调用方法
                    m.invoke(obj,null);            --4.servlet的destroy方法被调用

七、Servlet的自动加载:<load-on-startup>  

默认情况下,第一次访问servlet的时候创建servlet对象。如果servlet的构造方法或init方法中执行了比较多的逻辑代码,那么导致用户第一次访问sevrlet的时候比较慢。如果在<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>2</load-on-startup>
 </servlet>

标签里边的数字代表了调用的优先级,数字越小,越先被调用。

八、Servlet线程安全问题。

注意: Servlet对象在tomcat服务器是单实例多线程的。

因为servlet是多线程的,所以当多个servlet的线程同时访问了servlet的共享数据,如成员变量,可能会引发线程安全问题。

解决办法:

  1. 把使用到共享数据的代码块进行同步(使用synchronized关键字进行同步)
  2. 建议在servlet类中尽量不要使用成员变量。如果确实要使用成员,必须同步。而且尽量缩小同步代码块的范围。(哪里使用到了成员变量,就同步哪里!!),以避免因为同步而导致并发效率降低。

九、ServletConfig对象,学习ServletConfig对象(点击我,去学习)

十、ServletContext对象,学习ServletContext对象(点击我,去学习)

原文地址:https://www.cnblogs.com/lyjs/p/4868906.html