Servlet(2)

来源:互联网 发布:手机防盗警报器软件 编辑:程序博客网 时间:2024/06/05 00:54

一、伪代码演示Tomcat的内部代码运行

1)、通过映射找到servlet-class的内容,字符串:com.gqx.servlet.FirstServlet

2)、通过反射构造构造FirstServlet对象

  2、1 得到字节码(class)文件对象

  Class clazz=class.forName("com.gqx.servlet.FirstServlet");

  2、2调用无参的构造方法来构造对象

  Object obj =clazz.newInstance();  -->serlvet的构造方法被激活

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的生命周期

Servlet的自动加载

  默认情况下,第一次访问servlet的时候创建servlet对象。如果servlet的构造方法或init方法中执行了比较多的逻辑代码,那么导致用户第一次访问sevrlet的时候比较慢。         改变servlet创建对象的时机: 提前到加载web应用的时候!!!

         在servlet的配置信息中,加上一个<load-on-startup>即可!!

如下

复制代码
<servlet>    <servlet-name>LifeDemo</servlet-name>    <servlet-class>gz.itcast.c_life.LifeDemo</servlet-class>    <!-- 让servlet对象自动加载 -->    <load-on-startup>1</load-on-startup> <!-- 注意: 整数值越大,创建优先级越低!!-->  </servlet>
复制代码

有参的init方法和无参的init方法

  有参的init方法中实现了无参的init方法,其源代码中调用了this.init();所以我们一般都会在无参的init方法中写入代码

Servlet的多线程并发问题

  

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

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

 

解决办法:

         1)把使用到共享数据的代码块进行同步(使用synchronized关键字进行同步)

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

 

实例代码如下:

复制代码
package com.gqxing.servlet2;import java.io.IOException;import java.io.PrintWriter;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;public class ThreadDemo extends HttpServlet {        /**     * 多线程安全问题     * 案例:访问网站的第几个人数     */    int count=1;    public void doGet(HttpServletRequest request, HttpServletResponse response)            throws ServletException, IOException {        response.setContentType("text/html;charset=utf-8");        response.getWriter().write("你现在是当前网站的第"+count+"个访客!");        //为了效果,这里用sleep方法去让线程同步        try {            Thread.sleep(5000);        } catch (InterruptedException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }        //当多个线程同时访问这里获取相同的count值的时候会发生线程安全问题。        count++;    }}
复制代码

效果如图

这个时候要加入避免出现线程安全的机制

复制代码
package com.gqxing.servlet2;import java.io.IOException;import java.io.PrintWriter;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;public class ThreadDemo2 extends HttpServlet {        /**     * 多线程安全问题     * 案例:访问网站的第几个人数     */    int count=1;    public void doGet(HttpServletRequest request, HttpServletResponse response)            throws ServletException, IOException {        response.setContentType("text/html;charset=utf-8");        //为当前访问的线程加锁,        synchronized (ThreadDemo2.class) {//锁线程必须是唯一的,可以用当前的字节码对象            response.getWriter().write("你现在是当前网站的第"+count+"个访客!");        }            count++;    }}
复制代码

 

原创粉丝点击