zoukankan      html  css  js  c++  java
  • Servlet第二篇【Servlet实现线程安全及其他细节补充】

    一、Servlet是单例的

    (一)
    ​ 浏览器多次对Servlet的请求,一般情况下,服务器只创建一个Servlet对象,也就是说,Servlet对象一旦创建了,就会驻留在内存中,为后续的请求做服务,直到服务器关闭。

    (二)
    但是对于每次访问的请求对象和响应对象都是新的。对于每次访问请求,Servlet引擎都会创建一个新的HttpServletRequest请求对象和一个新的HttpServletResponse响应对象,然后将这两个对象作为参数传递给它调用的Servlet的service()方法,service方法再根据请求方式分别调用doXXX方法。

    二、Servlet与线程安全

    ​ 因为一个类型的Servlet只有一个实例对象,那么就有可能会出现一个Servlet同时处理多个请求,那么Servlet是否为线程安全的呢?答案:“不是线程安全的”。这说明Servlet的工作效率很高,但也存在线程安全问题!
    ​ 所以我们不应该在Servlet中随便创建成员变量,因为可能会存在一个线程对这个成员变量进行写操作,另一个线程对这个成员变量进行读操作。

    通常,会通过以下方法来解决线程安全问题:

    1、不要在Servlet中创建成员变量!创建局部变量即可!

    如果一个变量需要多个用户共享,则应当在访问该变量的时候,加同步机制synchronized (对象){}

    如果一个变量不需要共享,则直接在 doGet() 或者 doPost()定义。这样不会存在线程安全问题

    2、可以创建无状态成员!(该类中并没有其他成员变量,只有一些不涉及状态的方法)

    public class Servlet01 extends HttpServlet {
    	private User user;
    	
    	@Override
    	protected void doGet(HttpServletRequest req, HttpServletResponse resp)
    			throws ServletException, IOException {
    		System.out.println("doGet()...");
    	}
    	
    	@Override
    	protected void doPost(HttpServletRequest req, HttpServletResponse resp)
    			throws ServletException, IOException {
    		System.out.println("doPost()...");
    	}
    }
    
    class User{
    	public void sayHello(){
    		System.out.println("hello...");
    	}
    }
    

    3、可以创建有状态的成员,但状态必须为只读的!(只能取值,不能改变)

    public class Servlet02 extends HttpServlet {
    	private User user;
    	
    	@Override
    	protected void doGet(HttpServletRequest req, HttpServletResponse resp)
    			throws ServletException, IOException {
    		System.out.println("doGet()...");
    	}
    	
    	@Override
    	protected void doPost(HttpServletRequest req, HttpServletResponse resp)
    			throws ServletException, IOException {
    		System.out.println("doPost()...");
    	}
    }
    
    class User{
    	private String name;
    	private int age;
    	
    	public String getName() {
    		return name;
    	}
    
    	public int getAge() {
    		return age;
    	}
    }
    

    三、让服务器在启动时就创建Servlet

    ​ 默认情况下,服务器会在某个Servlet第一次收到请求时创建它。但其实也可以在web.xml中对Servlet进行配置,使服务器启动时就创建Servlet。

    在<servlet>中配置<load-on-startup>,其中给出一个非负整数!且该数越小,优先级越高!
    
    <servlet>
        <servlet-name>Servlet03</servlet-name>
        <servlet-class>com.zuobiao.servlet.Servlet03</servlet-class>
        <load-on-startup>0</load-on-startup> 
    </servlet>
        
    <servlet-mapping>
        <servlet-name>Servlet03</servlet-name>
        <url-pattern>/Servlet03</url-pattern>
    </servlet-mapping>
    

    如果在元素中配置了<load-on-startup>元素,那么服务器在启动时,就会装载并创建Servlet的实例对象、以及调用Servlet实例对象的init()方法。

    四、同一个Servlet可以被映射到多个URL上

    (一)
    <servlet>
        <servlet-name>Servlet04</servlet-name>
        <servlet-class>com.zuobiao.servlet.Servlet04</servlet-class>
        <load-on-startup>0</load-on-startup> 
    </servlet>
      
    <servlet-mapping>
        <servlet-name>Servlet4</servlet-name>
        <url-pattern>/AServlet</url-pattern>
        <url-pattern>/BServlet</url-pattern>
    </servlet-mapping> 
    

    无论我访问的是http://localhost:8080/AServlet还是http://localhost:8080/BServlet。我访问的都是Servlet04。

    注意:
    <url-pattern>是<servlet-mapping>的子元素,用来指定Servlet的访问路径,即URL。它必须是以“/”开头!

    (二)Servlet映射的URL可以使用通配符

    1、所谓通配符就是星号“*”,星号可以匹配任何URL前缀或后缀,使用通配符可以命名一个Servlet绑定一组URL,例如:

    路径匹配:
    <url-pattern>/servlet/*<url-patter>:/servlet/a、/servlet/b,都匹配/servlet/*;
    扩展名匹配:
    <url-pattern>*.do</url-pattern>:/abc/def/ghi.do、/a.do,都匹配 *.do;
    啥都匹配:
    <url-pattern>/*<url-pattern>:匹配所有URL;
    

    请注意,通配符要么为前缀,要么为后缀,不能出现在URL中间位置,也不能只有通配符。例如:/.do就是错误的,因为星号出现在URL的中间位置上了。.*也是不对的,因为一个URL中最多只能出现一个通配符。

    2、通配符是一种模糊匹配URL的方式,如果存在更具体的<url-pattern>,那么访问路径会去匹配具体的<url-pattern>

    1、看谁的匹配度高,谁就被选择
    2、*.扩展名的优先级最低
    

    例如:

    <servlet>
    	<servlet-name>hello1</servlet-name>
    	<servlet-class>com.zuobiao.servlet.Hello1Servlet</servlet-class>
    </servlet>
    <servlet-mapping>
    	<servlet-name>hello1</servlet-name>
    	<url-pattern>/servlet/hello1</url-pattern>
    </servlet-mapping>
    	
    <servlet>
    	<servlet-name>hello2</servlet-name>
    	<servlet-class>com.zuobiao.servlet.Hello2Servlet</servlet-class>
    </servlet>
    <servlet-mapping>
    	<servlet-name>hello2</servlet-name>
    	<url-pattern>/servlet/*</url-pattern>
    </servlet-mapping>
    

    当访问路径为http://localhost:8080/hello/servlet/hello1时,因为访问路径即匹配hello1的<url-pattern>,又匹配hello2的<url-pattern>,但因为hello1的<url-pattern>中没有通配符,所以优先匹配,即设置hello1。

    (三)Servlet映射的URL可以使用通配符和Servlet可以被映射到多个URL上的作用:

    1、隐藏网站是用什么编程语言写的【.php,.net,.asp实际上访问的都是同一个资源】

    2、特定的后缀声明版权【公司缩写】

    五、web.xml文件的继承(只是为了更好地理解从而比作继承)

    1、每个完整的JavaWeb应用中都需要有web.xml,但我们不知道所有的web.xml文件都有一个共同的父文件,它在Tomcat的conf/web.xml路径。

    2、在confweb.xml中的内容,相当于写到了每个项目的web.xml中,它是所有web.xml的父文件。

    3、在confweb.xml中,还分别有一个默认的Servlet和一个后缀为jsp的Servlet,部分源码如下:

     <servlet>
            <servlet-name>default</servlet-name>
            <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
            <init-param>
                <param-name>debug</param-name>
                <param-value>0</param-value>
            </init-param>
            <init-param>
                <param-name>listings</param-name>
                <param-value>false</param-value>
            </init-param>
            <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet>
            <servlet-name>jsp</servlet-name>
            <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
            <init-param>
                <param-name>fork</param-name>
                <param-value>false</param-value>
            </init-param>
            <init-param>
                <param-name>xpoweredBy</param-name>
                <param-value>false</param-value>
            </init-param>
            <load-on-startup>3</load-on-startup>
    </servlet>
    
    <servlet-mapping>
            <servlet-name>default</servlet-name>
            <url-pattern>/</url-pattern>
        </servlet-mapping>
    
        <servlet-mapping>
            <servlet-name>jsp</servlet-name>
            <url-pattern>*.jsp</url-pattern>
    </servlet-mapping>
    

    a. 该默认Servlet匹配所有URL,也就是说用户访问的URL路径没有匹配的页面时,那么执行的就是名为default的Servlet,如果它也不能处理则显示404。其实我们在访问index.html时也是在执行这个Servlet。

    b. 任何URL后缀为jsp的访问,都会执行名为jsp的Servlet

    Java新手,若有错误,欢迎指正!

  • 相关阅读:
    prototype.js超强的javascript类库
    MySQL Server Architecture
    Know more about RBA redo block address
    MySQL无处不在
    利用Oracle Enterprise Manager Cloud Control 12c创建DataGuard Standby
    LAMP Stack
    9i中DG remote archive可能导致Primary Database挂起
    Oracle数据库升级与补丁
    Oracle为何会发生归档日志archivelog大小远小于联机重做日志online redo log size的情况?
    Oracle Ksplice如何工作?How does Ksplice work?
  • 原文地址:https://www.cnblogs.com/Java-biao/p/12724553.html
Copyright © 2011-2022 走看看