标签:servlet
默认情况下,第一次访问servlet的时候创建servlet对象。 如果servlet的构造方法或init方法中执行了比较多的逻辑代码,那么就会导致用户第一次访问sevrlet的时候比较慢。
解决方法:改变servlet创建对象的时机,即提前到加载web应用的时候!!!
在servlet的配置信息中,加上一个<load-on-startup>即可!!
<servlet> <servlet-name>LifeDemo</servlet-name> <servlet-class>com.rk.http.b_lifecycle.LifeDemo</servlet-class> <!-- 让servlet对象自动加载 --> <load-on-startup>1</load-on-startup><!-- 注意: 整数值越大,创建优先级越低!! --> </servlet> <servlet-mapping> <servlet-name>LifeDemo</servlet-name> <url-pattern>/life</url-pattern> </servlet-mapping>
程序开发人员自定义的Servlet类,一般继承自javax.servlet.HttpServlet抽象类,而javax.servlet.HttpServlet类继承自javax.servlet.GenericServlet抽象类。javax.servlet.GenericServlet提供了两个init方法:
void init(ServletConfig config)
void init()
两者之间的简单关系如下:
//有参数的init方法 //该方法是servlet的生命周期方法,一定会被tomcat服务器调用 //注意:如果要编写初始代码,不需要覆盖有参数的init方法 public void init(ServletConfig config) throws ServletException { this.config = config; this.init(); } //无参数的init方法 //该方法是servlet的编写初始化代码的方法。 //是Sun公司设计出来专门给开发者进行覆盖,然后在里面编写servlet的初始逻辑代码的方法。 public void init() throws ServletException { }
javax.servlet.GenericServlet类的部分源码如下:
package javax.servlet; import java.io.IOException; import java.util.Enumeration; public class GenericServlet implements Servlet, ServletConfig, java.io.Serializable { private transient ServletConfig config; /** * Does nothing. All of the servlet initialization is done by one of the <code>init</code> methods. */ public GenericServlet() { } /** * Called by the servlet container to indicate that the servlet is being placed into service. */ public void init(ServletConfig config) throws ServletException { this.config = config; this.init(); } /** * A convenience method which can be overridden so that there‘s no need * to call <code>super.init(config)</code>. * * Instead of overriding init(ServletConfig), simply override * this method and it will be called by <code>GenericServlet.init(ServletConfig config)</code>. * The <code>ServletConfig</code> object can still be retrieved via getServletConfig. */ public void init() throws ServletException { } /** * Returns this servlet‘s ServletConfig object. */ public ServletConfig getServletConfig() { return config; } public String getServletName() { return config.getServletName(); } public String getInitParameter(String name) { return getServletConfig().getInitParameter(name); } public Enumeration getInitParameterNames() { return getServletConfig().getInitParameterNames(); } /** * Returns a reference to the ServletContext in which this servlet is running. */ public ServletContext getServletContext() { return getServletConfig().getServletContext(); } }
servlet对象在tomcat服务器是单实例多线程的。
因为servlet是多线程的,所以当多个servlet的线程同时访问了servlet的共享数据(如成员变量),可能会引发线程安全问题。
解决办法:
1)把使用到共享数据的代码块进行同步(使用synchronized关键字进行同步)
2)建议在servlet类中尽量不要使用成员变量。
a)如果确实要使用成员,必须同步;
b)尽量缩小同步代码块的范围,以避免因为同步而导致并发效率降低。(哪里使用到了成员变量,就同步哪里!!)
示例:记录页面访问次数
package com.rk.http.c_thread; 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; /** * servlet的多线程并发问题 * @author RK * */ public class ThreadDemo extends HttpServlet { private int count = 0; @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setCharacterEncoding("UTF-8"); response.setContentType("text/html;charset=utf-8"); PrintWriter out = response.getWriter(); // out.write("<html><head><title>访问次数</title></head><body>这是第N次访问本页面</body></html>"); out.write("<html><head><title>访问次数</title></head><body>这是第"); synchronized (ThreadDemo.class)//锁对象必须唯一。建议使用类对象 { try { Thread.sleep(3000);//这里模拟复杂的业务等待 } catch (InterruptedException e) { e.printStackTrace(); } count++; out.write("" + count); } out.write("次访问本页面</body></html>"); } }
标签:servlet
原文地址:http://lsieun.blog.51cto.com/9210464/1782118