活用DD, 比如, 我想设置一个email地址, 但是不像在servlet中硬编码, 如果能再web.xml中设置一个参数, 直接拿到这个参数就更好一点.

容器建立一个servlet时, 它会读DD(web.xml), 并为ServletConfig创建名/值对, 容器不会再读初始化参数了, 一旦参数放在ServletConfig中,就不会再读了. 除非你重新部署 servlet.

可见web.xml只读取一次, 所以如果你想修改点web.xml内容时, 就需要重新部署整个内容, 但是这比将内容写在servlet或Jsp中强一点,后者不仅要重新部署, 还要重新编译.

例如我想把email地址作为servlet 来响应的内容, 把它写在 web.xml 比在servlet中强, 因为不需要编译.

web.xml 中的初始化参数如下:

<servlet>

<init-param>

<param-name>abc</param-name>

<param-value>abc@123.com</param-value>

</init-param>

</servlet>

以上内容, 会作为一个参数名和值传给ServletConfig, 然后init()方法执行时, 会将这些内容读取, 只读取这一次

getServletConfig().getInitParameter("abc")  // 可以获得参数 abc的值 abc@123.com

另外, init 初始化参数只能针对某个特定的servlet, 即 <init-param> 要在 <servlet>内部

以上的 init 初始化参数, 只能 servlet 使用, jsp 不能使用, jsp如果想使用, 可以通过增加jsp属性的方法, 上一章有提过来增加, 但是这样做也不好, 解决办法是上下文初始化参数.

上下文初始化参数, 对整个Web应用而不只是对servlet可用. 并且, 上下文参数不在 <servlet>内部, 不是针对特定的 servlet.

<context-param>

<param-name>aaa</param-name>

<param-value>aaa@123</param-value>

</context-param>

在servlet中使用代码, getServletContext().getInitParameter(“aaa”);

上下文参数, 与普通 parameter 参数区别

容器在创建servlet时, 会读取DD, 并为ServletConfig创建 名/值对, 容器不会再读初始化参数了. 除非重新部署

成熟的 容器可以提供动态部署, 即不用关闭, 重启就可以部署.

每个 servlet 一个 servletConfig, 每个 Web应用一个 ServletContext

如果你希望应用初始化参数是一个数据库 datasource ? 不可能还利用xml来初始化数据库, 另外也不能把对象放到XML文件中来进行初始化啊?

如果 xml 能够激活一个对象或一个函数, 而这个对象或函数能够初始化对象和数据库(比如数据库连接, 关闭等), 所以就由了xml监听类.

xml中设置监听类

我们需要一个单独的对象, 它能做到:

上下文初始化时得到通知( 应用得到部署 )

  • 从ServletContext得到上下文的初始化参数
  • 使用初始化参数查找名建立一个数据库连接
  • 把数据库连接存储为一个属性, 使得web应用的各个部分都能访问

上下文撤销时得到通知 ( 应用取消部署或结束 )

  • 关闭数据库连接

容器通过web.xml 发现和使用监听者

用来初始化的对象

import javax.servlet.*;

public class MyServletContextListener implements ServletContextListener {

    public void contextInitialized(ServletContextEvent event) {
// 初始化数据库连接代码
// 并且保存这段连接代码为一个 context attribute
} public void contextDestoryed(ServletContextEvent event) {
// 关闭数据库连接的代码
}
}

<listener></listener>

process

例子:我们把String初始化参数转换为一个真正的对象, 一个 Dog

0. 首先创建一个监听者类 , 把它放在 WEB-INF/classes目录中, 并在部署描述文件中放一个<listener>元素来告诉容器.

package com.example;

import javax.servlet.*;

public class MyServletContextListener implements ServletContextListener {

    public void contextInitialized(ServletContextEvent event) {
// 由事件得到 ServletContext
servletContext sc = event.getServletContext();
// 使用上下文的到初始化参数
String dogBreed = sc.getInitParameter("breed");
// 根据参数建立对象
Dog d = new Dog(dogBreed);
// 使用上下文, 增加了属性
sc.setAttribute("dog", d);
} public void contextDestroyed(ServletContextEvent event) {
}
}

1. web.xml

<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0"
metadata-complete="true"> <servlet>
<servlet-name>Ch3 Beer</servlet-name>
<servlet-class>com.example.web.BeerSelect</servlet-class>
<init-param>
<param-name>adminEmail</param-name>
<param-value>admin@abc.com</param-value>
</init-param>
<init-param>
<param-name>mainEmail</param-name>
<param-value>main@abc.com</param-value>
</init-param>
</servlet> <servlet-mapping>
<servlet-name>Ch3 Beer</servlet-name>
<url-pattern>/web/SelectBeer.do</url-pattern>
</servlet-mapping>
<context-param>
<param-name>breed</param-name>
<param-value>Great Dane</param-value>
</context-param>
<listener>
<listener-class>
com.example.MyServletContextListener
</listener-class>
</listener> <servlet>
<servlet-name>Lis</servlet-name>
<servlet-class>com.example.ListenerTester</servlet-class>
</servlet> <servlet-mapping>
<servlet-name>Lis</servlet-name>
<url-pattern>/ListenTest.do</url-pattern>
</servlet-mapping> </web-app>

2. Dog class 只是一个比方, 连接数据库的内容类似

/*
* File: src/com/example/Dog.java
* --------------------------------
*/ package com.example; public class Dog {
private String breed; public Dog(String breed) {
this.breed = breed;
} public String getBreed() {
return breed;
}
}

3. Listener 主要用来实例化 Dog

/*
* File: src/com/example/MyServletContextListener.java
* -------------------------------------------
*/ package com.example; import javax.servlet.*; public class MyServletContextListener implements ServletContextListener { public void contextInitialized(ServletContextEvent event) {
// open database
ServletContext sc = event.getServletContext();
String dogBreed = sc.getInitParameter("breed");
Dog d = new Dog(dogBreed);
sc.setAttribute("dog", d); } public void contextDestroyed(ServletContextEvent event) {
// close database
}
}

4. Servlet, testlistener

/*
* File: src/com/example/ListenerTester.java
* --------------------------------------------
*/ package com.example; import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import com.example.*; public class ListenerTester extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
response.setContentType("text/html");
PrintWriter out = response.getWriter(); out.println("test context attributes set by listener<br />");
out.println("<br />"); Dog dog = (Dog) getServletContext().getAttribute("dog"); out.println("Dog's breed is: " + dog.getBreed()); }
}

5. 测试时, 只需要执行 http://localhost:8080/listenerTest/ListenTest.do

总结:首先, 容器在启动的时候, 会去读取 web.xml, 并实例化其中的<Listener> 类和servlet类,  并且将所有的上下文参数<context-param> 做成了 (key-value 对的形式交给servletContext), 注意:实例化<Listener>类时会调用contextInitialized()这个方法, 这个方法的实际意义是用来连接数据库的, 这个方法具体做什么事情, 你可以自己编写, 只不过这个方法可以访问到ServletContext所有的key和value对, 通过这些可以访问到得key和value, 来初始化数据库或者创建对象等等, 并将结果以 key, value的形式添加到 ServletContext的atribute中, 此时这个方法可以通过 getServletContext()获得<context-param>中的参数来进行一些处理, 例如连接数据库, 然后再将数据库连接的内容设置成servletContext的一个属性, 供所有人调用, 这个时候如果有别人需要请求时, 其他的servlet就可以调用这个属性来确认连接数据库. 由此可见, <Listener>会在容器启动时先运行并实例化完毕, 在哪里等待, 等待别的servlet调用 (本例中就是 ListenerTester).

这样也就实现了, 属性可以通过编程设置. 另外可以用很多类型的监听者, 不单单是监听上下文参数的.

另外要注意, 上下文属性是大家都能访问的, 换句话说, 它不是线程安全的.

其他的监听者

属性和参数的区别

上下文, 请求, 会话

多线程访问时, 属性也并非是安全的, 比如 A线程修改了一个属性的值, 而后B线程也修改了属性的值, 但是A不知道, A还以为属性是刚刚他修改的内容. 类似之前说的实例变量不安全, 一样.

RequestDispatcher 只有两个方法, forward() 和 include()

HeadFirst Jsp 05 (属性和监听)的更多相关文章

  1. vue2之对象属性的监听

    对象属性监听的两种方法: 1.普通的watch data() { return { frontPoints: 0 } }, watch: { frontPoints(newValue, oldValu ...

  2. 科学计算三维可视化---Traits属性的监听

    Traits属性的监听 HasTraits对象所有Traits属性都自动支持监听功能,当每个Traits属性发生变化时,HasTraits对象会通知监听此属性的函数 两种监听模式 静态监听 动态监听 ...

  3. Vue (表单、斗篷、条件、循环指令,分隔符成员、计算属性成员、属性的监听、vue组件、子组件、各个常见的钩子函数)

    表单指令 <!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF- ...

  4. vue双向数据绑定对于数组和新增对象属性不能监听的解决办法

    出现数组不能按照索引进行跟新的原因是处于性能考虑的,但是整体数组的增加删除是可以监听到的:对于对象新增属性不能监听是因为没有在生成vue实例时候放进watcher收集依赖. 首先我们先来了解vue数据 ...

  5. Vue计算属性和监听属性

    一.计算属性 计算属性关键词: computed.计算属性在处理一些复杂逻辑时是很有用的. 可以看下以下反转字符串的例子: <div id="app"> {{ mess ...

  6. asterisk-java ami3 属性改变监听

    asteriskServer.addAsteriskServerListener(new AsteriskListenerInit());//服务属性监听会自动连接服务 实现AsteriskServe ...

  7. vue computed计算属性 watch监听

    计算属性 computed:{ 变量:function(){ return 计算好的值 } } 这时候计算好的值 就付给了你的变量 在实例中可以this.使用 注意 声明的变量的data中不可以重复声 ...

  8. Vue-指令补充、过滤器、计数器属性、监听属性

    vue实例成员: el | template |data | methods watch 监听事件| computed 计数属性使用 | filters过滤器 | props 父传子 componen ...

  9. Zookeeper(2)---节点属性、监听和权限

    之前通过客户端连接之后我们已经知道了zk相关的很多命令(Zookeeper(1)---初识). 节点属性: 现在我们就通过stat指令来看看节点都有哪些属性,或者使用get 指令和-s参数来查看节点数 ...

随机推荐

  1. 在线编辑器 (UBB, FCK)

    这里主要说明一下:UBB UBB 使用类型HTML的语法.  UBB相对FCK的HTML方式, 安全性高. 用户不可以直接嵌入HTML代码.   UBB 在线编辑器(JS版): http://www. ...

  2. .NET设计模式(16):模版方法(Template Method)(转)

    摘要:Template Method模式是比较简单的设计模式之一,但它却是代码复用的一项基本的技术,在类库中尤其重要. 主要内容 1.概述 2.Template Method解说 3..NET中的Te ...

  3. CKEditor (Toolbar Definition)工具栏自定义配置

    JS是大小写敏感的, 在设置配置文件的时候需要注意 以CKEditor 4为基础我们可以通过两种方式配置CKEditor的工具栏,一种是是通过config.js配置文件设置, 另一种是IN-PAGE方 ...

  4. Git 10 周年之际,创始人 Linus Torvalds 访谈

    点这里 十年前的这一周,linux 内核社区面临一个根本性的挑战:他们不再能够使用他们的修复控制系统:BitKeeper,同时其他的软件配置管理遇到了对分布式系统的新需求.Linus Torvalds ...

  5. jvm性能调优---jstat的用法

    Jstat是JDK自带的一个轻量级小工具.全称“Java Virtual Machine statistics monitoring tool”,它位于java的bin目录下,主要利用JVM内建的指令 ...

  6. root 授权

    错误:The user specified as a definer ('root'@'%') does not exist 解决: grant all privileges on *.* to ro ...

  7. MapReduce实例

    1.WordCount(统计单词) 经典的运用MapReuce编程模型的实例 1.1 Description 给定一系列的单词/数据,输出每个单词/数据的数量 1.2 Sample a is b is ...

  8. java 时间戳与日期字符串相互转换

    /** * 时间戳转换成日期格式字符串 * @param seconds 精确到秒的字符串 * @param formatStr * @return */ public static String t ...

  9. http://www.cnblogs.com/TankXiao/p/4018219.html

    http://www.cnblogs.com/TankXiao/p/4018219.html

  10. SSH连接不上Linux的解决方法

    SSH连接不上Linux的解决方法: 连续弄了几次,今天早上终于把SSH连接虚拟机连接不通的问题解决了. 先简单说下概要: 主机装的是XP系统,虚拟机用的是red hat Linux. 我用的是nat ...