Servlet学习笔记(Servlet开发过程中的细节:映射、单例、获取配置信息等)

来源:互联网 发布:mac中如何替换ppt模版 编辑:程序博客网 时间:2024/06/05 22:34

一、一个已经注册的Servlet可以被多次映射

web.xml中:

  <servlet>    <description></description>    <display-name>Test1</display-name><!-- servlet的注册名 -->    <servlet-name>Test1</servlet-name><!-- servlet类的全路径(包名+类名) -->    <servlet-class>com.cn.Test1</servlet-class>  </servlet><!-- 对一个已经注册的servlet的映射 -->  <servlet-mapping><!-- servelt的注册名 -->    <servlet-name>Test1</servlet-name><!-- servlet的访问路径 -->    <url-pattern>/Test1</url-pattern>  </servlet-mapping><!-- 对一个已经注册的servlet的映射 -->  <servlet-mapping><!-- servelt的注册名 -->    <servlet-name>Test1</servlet-name><!-- servlet的访问路径 -->    <url-pattern>/cn</url-pattern>  </servlet-mapping>

由此可以看出,当映射一个servlet时候,可以多层 比如 :

<url-pattern>/servlet/index.html</url-pattern>

从这里还可以看出,后缀名是 html 不一定就是 html,可能是假象。

除了以上的一个Servlet可以被多次映射之外,还可以使用通配符在Servlet映射到url中。

有两种格式:
第一种格式 : * .扩展名 比如 * .do , * .ss
第二种格式 :以 / 开头 同时以 /* 结尾 比如 /* , /news/*
example:
假设有以下几种映射关系,
(1)Servlet1 映射到 /abc/*
(2)Servlet2 映射到 /*
(3)Servlet3 映射到 /abc
(4)Servlet4 映射到 *.do

问题:
(1) 当请求URL为“/abc/a.html”,“/abc/”和“/”都匹配,哪个servlet响应?
Servlet引擎将调用Servlet1。
(2)当请求URL为“/abc”时,“/abc/*”和“/abc”都匹配,哪个servlet响应?
Servlet引擎将调用Servlet3。
(3) 当请求URL为“/abc/a.do”时,“/abc/”和“.do”都匹配,哪个servlet响应?
Servlet引擎将调用Servlet1。
(4)当请求URL为“/a.do”时,“/”和“.do”都匹配,哪个servlet响应?
Servlet引擎将调用Servlet2。
(5)当请求URL为“/xxx/yyy/a.do”时,“/”和“.do”都匹配,哪个servlet响应?
Servlet引擎将调用Servlet2。

在匹配的时候,要参考的标准:
(1) 匹配度高的被优先选择
(2) *.do 的优先级最低

二、Servlet单例问题

当Servlet被第一次访问后,就被加载到内存,以后该实例对各个请求服务,即在使用中是单例.
因为 Servlet是单例,因此会出现线程安全问题,如售票系统. 如果不加同步机制,则会出现票务剩余异常的问题。
解决方法:
(1) 如果一个变量需要多个用户共享,则应当在访问该变量的时候,加同步机制:

synchronized (对象){    //同步代码}

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

三、servlet 中的 < load-on-startup > 配置

需求: 当我们的网站启动的时候,可能会要求初始化一些数据,(比如创建临时表), 在比如:网站有一些要求定时完成的任务[ 定时写日志、定时备份数据、定时发送邮件等等]
解决方法: 可以通过 < load-on-startup > 配合线程知识来完成。

<!-- 1表示该servlet被 init的顺序 --><load-on-startup>1</load-on-startup>

这部分也可以指定servlet被init的顺序。

简易模拟发送邮件项目:
SendEmailThread.java

package com.cn;public class SendEmailThread extends Thread{    @Override    public void run() {        // TODO Auto-generated method stub        int i=0;        try {            while(true){            //每休眠一分钟,就去扫描sendEmail表,检测哪一封信件需要发出            Thread.sleep(5*1000);            System.out.println("发出第"+(++i)+"封邮件");//这部分可以用javamail技术实现            }        } catch (Exception e) {            // TODO: handle exception        }    }}

同时在MyInitServlet1中的init()方法中做如下处理:

public void init(ServletConfig config) throws ServletException {        // TODO Auto-generated method stub        System.out.println("MyInitSevlet1初始化...");        //完成一些初始化任务        System.out.println("创建表...读取参数...");        //创建一个线程        SendEmailThread s=new SendEmailThread();        s.start();    }

四、ServletConfig对象

该对象主要用于 读取 servlet的配置信息。
web.xml中有Servlet的一些配置,如下面的代码所示:

<servlet>    <description></description>    <display-name>MyInitServlet1</display-name>    <servlet-name>MyInitServlet1</servlet-name>    <servlet-class>com.cn.MyInitServlet1</servlet-class><!-- 这里可以给servlet配置信息,这里配置的信息,只能被MyInitServlet1 读取 -->    <init-param>    <param-name>encoding</param-name>    <param-value>utf-8</param-value>    </init-param>    <init-param>    <param-name>author</param-name>    <param-value>cn</param-value>    </init-param>    <init-param>    <param-name>version</param-name>    <param-value>1.0</param-value>    </init-param>    <load-on-startup>1</load-on-startup>  </servlet>

读取参数的方法:(案例中访问ServletConfigTest将参数全部获取并打印到页面上)
ServletConfigTest.java

String encoding=this.getServletConfig().getInitParameter("encoding");

补充:这种配置参数的方式,只能被某个Servlet独立使用.如希望让所有的Servlet都去读取某个参数,这样配置:

<!-- 如果这里配置参数,可被所有servlet读取 --> <context-param>  <param-name>author</param-name>  <param-value>cn</param-value>  </context-param>

如果要把所有的参数都读取,则使用 如下方法 :

Enumeration<String> names=this.getInitParameterNames();        while (names.hasMoreElements()) {            String name = names.nextElement();            out.println(name);            out.println(this.getServletConfig().getInitParameter(name));        }
0 0