1. 应用程序事件以及事件监听:
1) 在Web容器中,各个Servlet/JSP都是应用程序,在应用程序生命周期中会发生很多事件,最典型的事件就是生成和销毁;
2) Web容器为这些应用程序事件提供了监听器,当这些事件发生时监听器会响应并作出相应的处理,处理代码需要用户自己实现,就和Windows的消息响应机制一样;
3) Web容器主要为HttpServletRequest、HttpSession、ServletContext这三种对象提供了监听器,接下来也主要围绕这三者的监听器展开;
2. ServletContext事件、监听器:
1) 和环境有关的监听器有两类,一类是ServletContextListener(监听应用程序初始化和销毁事件),另一类是ServletContextAttributeListener(监听ServletContext的属性被添加、删除和替换事件),这里主要介绍ServletContextListener;
2) ServletContextListener接口原型:
public interface ServletContextListener extends EventListener { public void contextInitialized(ServletContextEvent sce); public void contextDestroyed(ServletContextEvent sce); }i. 注意!事件的时间点是应用程序初始化“后”(即调用了init(config: ServletConfig)后,但init()还没调用!),和程序在被销毁“前”;
ii. 可以在contextInitialized中实现应用程序相关资源的准备动作,比如数据库的连接、读取程序的配置信息等,而在contextDestroyed中可以实现应用程序资源的释放动作,如断开数据库连接,还有一些C++本地代码的内存释放等;
3) ServletContextEvent类只有一个方法,那就是getServletContext方法,获取的还是应用程序ServletConfig中的ServletContext,和Servlet类的getServletContext一模一样;
!!获取ServletContext后就可以进行更多的操作了,如getInitParameter、setAttribute等,特别是getInitParameter来获取初始参数,因此Web应用程序的初始参数也常被成为ServletContext的初始参数;
4) 实现该接口的类必须用@WebListener进行标注,例如:
@WebListener public class ContextParameterReader implements ServletContextListener { public void contextInitialized(ServletContextEvent sce) { ServletContext context = sce.getServletContext(); String iconPath = context.getInitParameter("ICON_PATH"); context.setAttribute("ICON_PATH", iconPath); } public void contextDestroyed(ServletContextEvent sce) {} }!!标注@WebListener是给Web容器看的,表明该类是一个Web事件监听器,里面的每一个方法都必须实现!!
!!由于@WebListener标注是无属性的,因此要设置其属性就必须到web.xml中设置,也只有这一种方法来设置应用程序的环境参数:
a. <context-param>:环境参数标签
b. 底下的<param-name>和<param-value>来设置参数的名称和值
c. 例如:
<context-param> <param-name>ICON_PATH</param-name> <param-value>/icon</param-value> </context-param>!!很显然,上面的演示是在从配置中读取程序中要用到的头像的路径;
5) 由于初始化事件的监听并响应是发生在init(config: ServletConifg)后和init()前,上面演示中context的ICON_PATH对象在init()中就已经存在,此时可以在init()中用该环境属性来初始化自定义HttpServlet类中的一些自定义数据成员了,比如:
@WebServlet("/icon.view") public class Icon extends HttpServlet { private String ICON_PATH; @Override public void init() throws ServletException { ICON_PATH = (String)getServletContext().getAttribute("ICON_PATH"); } }
!!!Web应用初始化的标准步骤:
a. 理应使用context监听器进行初始化,即使用context-param初始化,而不是init-param来初始化,init-param可以应用于一些小的工程,但对于一些大的、复杂的工程应该使用context-param加监听器的方法进行初始化;
!!原则和MFC编程一样,用户应把精力集中在处理事件的逻辑上,而不是专注于事件发生的时间点上;
b. 步骤总结:context-param中配置环境参数 -> contextInitialized中读取并设置配置参数 -> init()中提取环境参数并初始化自定义数据成员;
c. 使用监听器初始化的好处就是大大简化了@WebServlet标注,只需要写一个url模式即可,不用在写很多默认的config参数,而是直接从context中提取想要的参数即可;
6) 使用监听器初始化的典型案例——设置HttpSession的Cookie:
i. 之前讲过要设置HttpSession的Cookie必须要使用web.xml,但是ServletContext有个方法,就是getSessionCookieConfig(),可以获取SessionCookieConfig对象,该对象有一系列方法,如setName等来配置Session的Cookie;
ii. 但是Session Cookie是在init()之前就已经配置完毕,如果要在init()中修改则这些修改都是无效的,而刚好在init(config: ServletConfig)之后Session Cookie还没配置,因此可以利用ServletContextListener在这个时机点对Session Cookie进行配置:
@WebListener public class Test implements ServletContextListener { public void contextInitialized(ServletContextEvent sce) { ServletContext context = sce.getServletContext(); context.getSessionCookieConfig().setName("my-sessionId"); } public void contextDestroyed(ServletContextEvent sce) {} }!这里就将Tomcat默认的JSESSIONID改成了my-sessionId了;
!!在Servlet3.0之前,Web监听器必须在web.xml中声明,否则Web容器无法识别:
<listener> <listener-class>com.lirx.TestListener</listener-class> </listener>!!标签就是<listener>和<listener-class>;
!!而3.0之后@WebListener标签就取代了web.xml的<listener>标签的功能了;
3. ServletContextAttribute事件、监听器:
1) 监听器是ServletContextAttributeListener,用于监听并响应ServletContext属性的添加、删除和替换;
2) 接口原型:
public interface ServletContextAttributeListener extends EventListener { public void attributeAdded(ServletContextAttributeEvent scae); public void attributeRemoved(ServletContextAttributeEvent scae); public void attributeReplaced(ServletContextAttributeEvent scae); }
3) 所有Web监听器要么用@WebListener标注,要么就在web.xml中配置<listener>标签,这个也不例外;
4) ServletContextAttributeEvent类中只包装了String getName();和Object getValue();两个方法,用来获取被加入、删除或是替换的那个属性的名称和值;