• Servlet的监听


    Servlet监听

    在《Servlet和Jsp》中我们使用了ServletConfig获取Servlet的初始配置,用ServletContext来获取整个Web应用的初始配置,但如果需要在所有的Servlet之前初始化资源怎么办呢?比如DataSource、Log4j等,可惜Servlet没有main方法,它是靠Web容器(如Tomcat)来加载的。

    幸运的是Servlet提供了一个类javax.servlet.ServletContextListener,它能够监听ServletContext一生中的两个关键事件:初始化(创建)和撤销。

    小示例

    新建net.oseye.web.listener.MyTestContextListener类实现javax.servlet.ServletContextListener:

    public class MyTestContextListener implements ServletContextListener {
    
    	public void contextInitialized(ServletContextEvent arg0) {
    		//通过ServletContext传递资源
    		arg0.getServletContext().setAttribute("name", "kevin");
    	}
    
    	public void contextDestroyed(ServletContextEvent arg0) {
    		// 不需要销毁资源
    	}
    }

    在DD文件中配置Context监听:

    <!DOCTYPE web-app PUBLIC
     "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
     "http://java.sun.com/dtd/web-app_2_3.dtd" >
    
    <web-app>
      <display-name>Archetype Created Web Application</display-name>
      
      <listener>
      	<listener-class>net.oseye.web.listener.MyTestContextListener</listener-class>
      </listener>
    
      <servlet>
      	<servlet-name>HelloOther</servlet-name>
      	<display-name>HelloOther</display-name>
      	<description></description>
      	<servlet-class>net.oseye.web.HelloOther</servlet-class>
      </servlet>
    
      <servlet-mapping>
      	<servlet-name>HelloOther</servlet-name>
      	<url-pattern>/HelloOther</url-pattern>
      </servlet-mapping>
    
    </web-app>

    在Servlet中获取Context值并使用:

    String name=(String) getServletContext().getAttribute("name");
    response.getWriter().println("name:"+name);

    Servlet中使用Log4J

    Log4j的配置文件在项目中的位置如下图:

    log4j.properties内容

    log4j.logger.net.oseye=INFO,WebFile
    
    log4j.appender.WebFile=org.apache.log4j.DailyRollingFileAppender 
    log4j.appender.WebFile.File=d:/log/testweb/web.log
    log4j.appender.WebFile.DatePattern=yyyy-MM-dd-HH'.log'
    log4j.appender.WebFile.layout=org.apache.log4j.PatternLayout
    log4j.appender.WebFile.layout.ConversionPattern=%d{HH:mm:ss,SSS} %M %m%n

    在pom.xml中添加slf4j依赖

    <dependency>
    	<groupId>org.slf4j</groupId>
    	<artifactId>slf4j-log4j12</artifactId>
    	<version>1.7.6</version>
    </dependency>

    web.xml配置监听

    <listener>
    	<listener-class>
    		net.oseye.web.listener.MyTestContextListener
    	</listener-class>
    </listener>

    net.oseye.web.listener.MyTestContextListener监听类代码

    public class MyTestContextListener implements ServletContextListener {
    
    	public void contextInitialized(ServletContextEvent arg0) {
    		//通过ServletContext传递资源
    		arg0.getServletContext().setAttribute("name", "kevin");
    		PropertyConfigurator.configure(arg0.getServletContext().getRealPath("/config/log4j.properties"));
    	}
    
    	public void contextDestroyed(ServletContextEvent arg0) {
    		// 不需要销毁资源
    	}
    }

    在Servlet中记录日志

    Logger logger=LoggerFactory.getLogger(HelloOther.class);
    logger.info("测试Log4j");

    监听器

    只要是在生命周期里的重要时刻,总会有一个监听器在监听,下面是8个监听器

    场景 监听器接口 时间类型
    你想知道一个web应用上下文中是否增加、删除或替换了一个属性

    javax.servlet.ServletContextAttributeListener
    attributeAdded
    attributeRemoved
    attributeReplaced

    ServletContextAttributeEvent
    你想知道有多少个并发用户,也就是说,你想跟踪活动的会话

    javax.servlet.http.HttpSessionListener
    sessionCreated
    sessionDestroyed

    HttpSessionEvent
    每次请求到来时你都想知道,以便建立日志记录

    javax.servlet.ServletRequestListener
    requestInitialized
    requestDestroyed

    ServletRequestEvent
    增加、删除或替换一个请求属性时你希望能够知道

    javax.servlet.ServletRequestAttributeListener
    attributeAdded
    attributeRemoved
    attributeReplaced

    ServletRequestAttributeListener
    你有一个属性类,而且你希望这个类型的对象在绑定到一个会话或从会话中或从会话删除时得到通知

    javax.servlet.HttpSessoinBindingListener
    valueBound
    valueUnbound

    HttpSessionBindingEvent
    增加、删除或添加一个会话属性时你希望能够知道

    javax.servlet.HttpSessionAttributeListener
    attributeAdded
    attributeRemoved
    attributeReplaced

    HttpSessionBindingEvent
    你想知道是否创建或撤销了一个上下文

    javax.servlet.ServletContextListener
    contextInitializated
    contextDestroyed

    ServletContextEvent
    你有一个属性类,而且希望这个类型的对象在其绑定的会话迁移到另一个JVM时得到通知

    javax.servlet.http.HttpSessionActivationListener
    sessionDidActivite
    sessionWillPassivate

    HttpSessionEvent

    HttpSessionListener和HttpSessionActivationListener共用HttpSessionEvent事件;ServletSessionBindingListener和ServletSessionAttributeListener共用HttpSessionBindingEvent事件。
    如在部署描述文件web.xml添加监听

    <listener>
    	<listener-class>net.oseye.web.listener.ContextAttributeListener</listener-class>
    </listener>
    <listener>
    	<listener-class>net.oseye.web.listener.SessionLinstener</listener-class>
    </listener>

    net.oseye.web.listener.ContextAttributeListener

    public class ContextAttributeListener implements ServletContextAttributeListener {
    	private static Logger logger=LoggerFactory.getLogger(ContextAttributeListener.class);
    	
    	public void attributeAdded(ServletContextAttributeEvent arg0) {
    		logger.info("name:{} val:{}",arg0.getName(),arg0.getValue().toString());
    
    	}
    
    	public void attributeRemoved(ServletContextAttributeEvent arg0) {
    		// TODO Auto-generated method stub
    
    	}
    
    	public void attributeReplaced(ServletContextAttributeEvent arg0) {
    		// TODO Auto-generated method stub
    
    	}
    }

    net.oseye.web.listener.SessionLinstener

    public class SessionLinstener implements HttpSessionListener {
    	private static Logger log=LoggerFactory.getLogger(SessionLinstener.class);
    		
    	public void sessionCreated(HttpSessionEvent arg0) {
    		log.info("创建-"+arg0.getSession().getId());
    	}
    
    	public void sessionDestroyed(HttpSessionEvent arg0) {
    		log.info("销毁-"+arg0.getSession().getId());
    	}
    }

    对于ServletContextAttributeListener我的测试只能监听ServletContext()操作的属性,而对于在DD文件中的却没能监听到,如web.xml配置:

    <context-param>
    	<param-name>email</param-name>
    	<param-value>kevin@oseye.net</param-value>
    </context-param>

    PS:这里是我理解错误,把属性和上下文参数搞混了,在web.xml中配置的是上下文参数。


    Context属性和会话属性的多线程

    Context属性和会话属性因为作用域很大,所以他们不是线程安全的,我们一般这样保证线程安全

    synchronized (getServletContext()) {
    	getServletContext().setAttribute("name", "kevin");
    	getServletContext().setAttribute("age", "22");
    }
    
    synchronized (request.getSession()) {
    	request.getSession().setAttribute("name", "kevin");
    	request.getSession().setAttribute("age", "22");
    }

    PS:每个Servlet只有一个实例对象(Instance),但可以被多个线程访问;这里强调这点并不是为了解释上面的属性线程不安全,因为即使是多个实例对象,也会有多个Servlet造成属性线程不安全的。

  • 相关阅读:
    使用CSS3的appearance属性改变元素的外观
    纯CSS 实现tooltip 内容提示信息效果
    移动端UC /QQ 浏览器的部分私有Meta 属性
    HTML5 的 applicationCache 应用程序缓存离线存储功能与 manifest 文件
    web移动端性能调优及16ms优化
    移动端HTML5资源整理
    js身份证验证-超级准!!!
    编写高效的js/jQuery代码 :rocket:
    html5 摇一摇事件监听
    ios7隐藏系统底部导航
  • 原文地址:https://www.cnblogs.com/zhaiqianfeng/p/4622478.html
Copyright © 2020-2023  润新知