• 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新手,若有错误,欢迎指正!

  • 相关阅读:
    并查集分析+总结
    poj 3083 Children of the Candy Corn(bfs+dfs 数组模拟方向)
    poj 1094 Sorting It All Out (拓扑排序)
    poj 2632 Crashing Robots(模拟)
    poj 1068 Parencodings (模拟)
    poj 1273 Drainage Ditches ( 最大流Edmonds_karp算法)
    poj 3278 Catch That Cow (BFS)
    Codeforces Round #109 (Div. 2) 总结
    poj 2299 UltraQuickSort(归并排序)
    poj 1035 Spell checker(字符串)
  • 原文地址:https://www.cnblogs.com/Java-biao/p/12724553.html
Copyright © 2020-2023  润新知