细节4servlet单例问题

①当servlet被第一次访问后,就被加载到内存,以后该实例对各个请求服务,即在使用中是单例的(可以设置全局变量i,然后再doget中i++,并输出该i,则在不同浏览器中或者不同的用户都能看到i加后的结果,并且i就像共享变量一样都能访问i不断加后的结果)。

②因为servlet是单例,因此会出现线程安全问题。这个实例在web退出/reload时实例才会消失。

③在servlet的整个生命周期内,servlet的init方法只被调用一次。对一个servlet的每次访问请求都导致servlet引擎调用一次servlet的service方法。每次访问请求,servlet引擎都会创建一个新的httpservletrequest请求和一个新的httpservletresponse响应对象,然后将这两个对象作为参数传递给它调用的service()方法,service方法再根据请求方式分别调用doxxx方法。

线程安全解决原则:

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

synchronized(对象){共享变量代码}

(2)如果一个变量不需要共享,则只需在doGet或者doPost中定义即可,也不会出现线程不安全问题,是个局部变量

细节5:load-on-startup配置

​load-on-startup​​配置,中的数据代表init执行次序

需求:当网站启动的时候,可能需要初始化一些数据(比如创建临时表、网站有一些定时完成的任务(定时写日志、定时备份数据库、定时发送邮件))

解决方法:可以通过​​load-on-startup​​和线程知识搞定

先说明​​load-on-startup​​​,通过配置​​load-on-startup​​我们可以指定某个servlet自动创建。

//简单理解
public void init() throws ServletException {
System.out.println("inti被执行......");
}
<servlet>
<servlet-name>demo2</servlet-name>
<servlet-class>com.TongPeiFu.demo2</servlet-class>
<!-- 1表示init启动的顺序 -->
<load-on-startup>1</load-on-startup>
</servlet>


需求:模拟电子邮件定时发送

public class sendemailThread extends Thread {
public void run()
{
int i=0;
try{
while(true){
Thread.sleep(10*1000);
System.out.println("发出第"+(++i)+"邮件");
}
}catch(Exception e){
e.printStackTrace();

}

}
}
public class demo2 extends HttpServlet {
public void init() throws ServletException {
System.out.println("inti被执行......");
//创建一个线程
sendemailThread s=new sendemailThread();
s.start();
}
}
public class demo3 extends HttpServlet {
public void init() throws ServletException {
System.out.println("demo3 inti被执行......");
}

}
<servlet>
<servlet-name>demo2</servlet-name>
<servlet-class>com.TongPeiFu.demo2</servlet-class>
<!-- 1表示init启动的顺序 -->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet>
<servlet-name>demo3</servlet-name>
<servlet-class>com.TongPeiFu.demo3</servlet-class>
<load-on-startup>2</load-on-startup>

</servlet>


细节6:ServletConfig对象:读取servlet的配置信息

(3)servlet单例问题、load-on-startup、ServletConfig_配置信息

public class configTest extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {

response.setContentType("text/html");

String encoding1=this.getServletConfig().getInitParameter("encoding");
response.setCharacterEncoding(encoding1);
response.getWriter().println("编码是:"+encoding1);
}
}
<servlet>
<servlet-name>configTest</servlet-name>
<servlet-class>com.TongPeiFu.configTest</servlet-class>
<!-- 这里可以给servlet配置信息,这里配置的信息,只能被该servlet读取 -->
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</servlet>


补充说明①:这种配置参数的方式,只能被某个servlet独立使用,若希望让所有的servlet都读取某个参数,则如下配置:

<!-- 这里配置的参数,可以被所有的servlet读取 -->
<context-param>
<param-name></param-name>
<param-value></param-value>
</context-param>


补充说明②:可以读取所有的配置信息,使用如下方法getInitParameterNames()

  <servlet>
<servlet-name>configTest</servlet-name>
<servlet-class>com.TongPeiFu.configTest</servlet-class>
<!-- 这里可以给servlet配置信息,这里配置的信息,只能被该servlet读取 -->
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>

<init-param>
<param-name>version</param-name>
<param-value>1.0</param-value>
</init-param>
<init-param>
<param-name>author</param-name>
<param-value>zhangsan</param-value>
</init-param>
</servlet>


public void doGet(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

     response.setContentType("text/html"); 
Enumeration<String> names=this.getServletConfig().getInitParameterNames();
while(names.hasMoreElements())
{
String name=names.nextElement();
String value=this.getServletConfig().getInitParameter(name);
response.getWriter().println("name:"+name+"-----"+"value:"+value);

}
}