继承图
Servlet<---GenericServlet<---HttpServlet<---MyServlet
大多数servlet方法来自GenericServlet doGet doPost doHead do...方法都在HttpServlet中
==============================================================================
作为Web应用
初始化参数 eg 在DD中配置email地址 而不是硬编码到servlet类中
out.println("[email protected]"); 要改email 不用每次都冲洗编译servlet 只要写DD就可以了
DD文件
<servlet>
<servlet-name>Ch3 Beer</servlet-name>
<servlet-class>com.example.web.BeerSelect</servlet-class>
<init-param>
<param-name>adminEmail</param-name>
<param-value>[email protected]</param-value>
</init-param>
</servlet>
在servlet代码中
out.println(getServletConfig().getInitParameter("adminEmail"));
在servlet初始化之前不能使用servlet初始化参数
容器初始化一个servlet时 会为中国servlet建一个唯一的ServletConfig
容器从DD读出servlet初始化参数 并把这些参数交给ServletConfig 然后ServletConfig传递给init方法
servlet初始化参数只能读一次 就是在容器初始化servlet的时候 一旦参数放在ServletConfig中 就不会再读
了 除非你重新部署servlet
过程
1.容器读取这个servlet的DD 包括servlet的初始化参数
2.容器为这个servlet创建一个新的ServletConfig实例 容器---new了--->ServletConfig
3.容器为每个servlet初始化参数创建一个String名/值对,假设这里只有一个初始化参数
4.容器向ServletConfig提供名/值初始化的引用
5.容器创建servlet类的一个实例!!!!!!!!!!!!!!!!!!!!!!(这里才创建实例 用了构造函数)
6.容器调用servlet的init()方法传入ServletConfig
上下文初始化参数 context 上下文;语境;环境
上下文参数对整个Web应用而不只是一个servlet可用 所以 应用中所有的servlet和JSP都自动的能访问
上下文初始化参数 我们不必费心为每个servlet配置DD 而且如果值有变化 只需在一个地方修改就行
<context-param>
<param-name>adminEmail</param-name>
<param-value>[email protected]</param-value>
</context-param>
==============================================================================
监听者
我们需要一个单独的类 它能做到
1.上下文初始化时得到通知(应用得到部署)
i.从ServletContext得到上下文初始化参数
ii.使用初始化参数查找名建立一个db连接
iii.吧数据库连接存储作为一个属性 使得Web应用的各个部分都可以访问
2.上下文撤销的时候得到通知(应用取消部署或者结束)
关闭数据库
一个Listerner的例子
---MyServletListener.java
package com.example; import javax.servlet.*; public class MyServletListener implements ServletContextListener { @Override public void contextInitialized(ServletContextEvent event) { //由事件得到ServletContext ServletContext sc = event.getServletContext(); //使用上下文得到初始化参数 String dogBreed = sc.getInitParameter("breed"); Dog d = new Dog(dogBreed); //使用上下文属性来设置属性(name/object)对这个属性是Dog 现在用其他部分就能得到属性(Dog)的值了 Attribute:属性 sc.setAttribute("dog", d);//vodi setAttribute } @Override public void contextDestroyed(ServletContextEvent servletContextEvent){} }
---Dog.java
package com.example; /** * Created by Melody on 2015/10/31. */ public class Dog { private String breed; public Dog(String breed) { this.breed = breed; } public String getBread() { return breed; } }
---ListenerTester.java
package com.example; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; /** * Created by Melody on 2015/10/31. */ public class ListenerTester extends HttpServlet { @Override protected void doGet(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException { PrintWriter out = response.getWriter(); out.println("test context attributes set by listener<br/>"); out.println("<br/>"); //getServletContext 返回ServletContext(是个对象 一切皆对象) getAttribute返回的是Object!!!!!!!!!切记 //getInitParameter() returns String Dog dog = (Dog) getServletContext().getAttribute("dog"); out.println("Dog‘s breed is: " + dog.getBread()); } }
http://localhost:8080/listenerTest/ListenTest.do
Servlet类名: ListenerTester.class
Web应用目录: listenerTest
映射到servlet的URL模式: ListenTest.do
完整的故事
1.容器读这个应用的DD(web.xml) 包括<listener>和<context-param>
2.容器为这个应用创建一个新的ServletContext 应用的所有部分都会共享这个上下文
容器---new了--->SservletContext
3.容器为每个上下文初始化参数创建一个String名/值对 这里假设只有一个参数
容器---new了--->"breed"(String) | 来自DD的上下文初始化参数 |
|---new了---->"Great Dane"(String) |_________________________|
4.容器将名/值参数的引用交给ServletContext(传递引用)
ServletContext------>"breed"(String)
|------>"Great Dane"(String)
5.容器创建MyServletContextListener类的一个新实例
容器---new了--->MyServletContextListener.class的实例
6.容器调用监听者的contextInitialized()方法 传入新的ServletContextEvent 这个事件对象有一个
ServletContextEvetn引用 所以事件处理代码可以从事件得到上下文初始化参数
ServletContext|------>"breed"(String)
|------>"Great Dane"(String)
↑
ServletContextEvent
↓
容器------contextInitialized(ServletContextEvent)--->监听者
7.监听者向ServletContextEvent要ServletContext的一个引用
监听者--getServletContext()-->ServletContextEvent(这样写是一个对象) 现在监听者得到ServletContext
8.监听者向ServletContext要上下文初始化参数"breed"
监听者--getInitParameter("breed")-->ServletContext(这样写是一个对象) |------>"breed"(String)
|------>"Great Dane"(String)
现在监听者得到上下文初始化参数"breed"
9.监听者使用初始化参数来构造一个新的Dog对象
监听者---new了--->Dog.class
10.监听者吧Dog设置为ServletContext中的一个属性
监听者--setAttribute("dog", d)--->ServletContext(对象)
11.容器建立一个新的servlet(利用初始化参数建立一个新的ServletConfig,为这个ServletConfig提供Servlet
Context的要给引用 然后调用servlet的init()的方法)
ServletContext|------>"breed"(String)
|------>"Great Dane"(String)
↑
ServletConfig
↓
容器------init(ServletConfig)--->ListenerTester.class(这个是servlet 也是controller)的实例
12.servlet得到一个请求 向ServletContext请求属性"dog"
Servelt---getAttribute("dog")--->ServletContext(对象)
13.servlet在Dog上调用getBread() 并将结果打印到HttpResponse
Servlet---getBread()--->Dog(对象)
监听者不只是针对上下文事件只要是生命周期里的重要时刻 总有一个监听者在监听
除了上下文事件之外 还可以监听与上下文属性 servlet请求和属性 以及HTTP会话和会话属性相关的事件
web应用上下文中是否增加 删除或替换了一个属性 监听者接口 ServletContextAttributeListener
attributeAdded attributeRemoved attributeReplaced
想跟踪活动的会话 HttpSessionListener
sessionCreated sessionDestroyed
每次请求到的时候你都想知道以便建立日志记录 ServletRequestListener
requestInitalized requestDestroyed
你想知道什么时候增加删除或者替换一个属性 ServletRequestAttributeListener
attributeAdded attributeRemoved attributeReplaced
你有个属性类 这个类型的对象绑定到一个会话或从会话删除时得到通知 HttpSessionBindingListener
valueBound valueUnbound
你想知道什么时候增加删除或替换一个会话属性 HttpSessionAttributeListener
attributeAdded attributeRemoved attributeReplaced
你想知道是否创建或撤销了一个上下文 ServletContextListener
contextInitialized contextDestroyed
你有一个属性表 而且希望此类对象绑定的会话迁移到另一个JVM时得到通知 HttpSessionActivationListener sessionDidActvie sessionWillPassivate
到底什么是属性
属性就是一个对象
设置(也称为绑定)到另外三个servlet API对象中---ServletContext HttpServletRequest(这个放到请求中以便
JSP/view能看到这个值)或者HttpSession 可以简单吧它认为是一个映射实例对象中的名/值对
(String/Object) 我们关心的只是属性所在的作用域 换句话说我们关心谁能看到这个属性以及属性能存活
多久
属性就像钉到公告栏上的一个对象 有人在公告栏上贴公告 以便其他人看到
这里有一个关键的问题:谁能访问公告栏 公告栏能存在多久 换句话说 属性的作用域是什么
属性不是参数
属性的设置方法是setAttribute(String name, Object value) 返回类型是Object 获取方法是
Object getAttribute(String name)
参数的是在DD中设置 返回String 获取方式是String getInitParameter(String name)
三个作用域 上下文 请求和会话
上下文属性(Context) 应用中的每一个部分都可以访问
会话属性(HttpSession) 能访问特定HttpSession的部分才能访问
请求属性(Request) 能访问特定ServletRequest的部分才能访问
上下文作用域不是线程安全的 应用中的每一部分都可以访问上下文属性
这意味着有多个servlet 多个servlet则说明你有多个线程 请求是并发处理的 每个请求在一个单独的线程
中处理 不论这些请求针对的是同一个servlet还是不同的servlet 但是servlet实例只会有一个 但可以有多个线程