Servlet监听器(附带spring中监听器使用分析)
2017-03-22 15:03
246 查看
一.简介
Servlet监听器 是Servlet规范中定义的一种特殊类 ,或者说一种高级特性.常用于监听request,session,context的创建,销毁或属性改变
二.监听器分类及作用(Servlet3.0规范)
eclipse里创建listener所提供的监听器接口
1.ServletContextListener
, SerlvetContextAttributeListener 用于监听应用程序环境对象(ServletContext)
在web.xml中配置<context-param> <param-name>begincode</param-name> <param-value>code</param-value> </context-param>
//在实现ServletContextListener接口中 public void contextInitialized(ServletContextEvent arg0) { String value = arg0.getServletContext().getInitParameter("begincode"); System.out.println(value); //code }
当 Servlet 容器启动后,会部署和加载所有 web 应用。当web 应用被加载,Servlet 容器会创建一次 ServletContext,然后将其保存在服务器的内存中。web 应用的 web.xml 被解析,找到其中所有 servlet、filter 和 Listener 或 @WebServlet、@WebFilter 和 @WebListener 注解的内容,创建一次并保存到服务器的内存中。ServletContext 与 web 应用存活时间一样长。它被所有 session 中的所有请求共享。
主要用途:作为定时器、加载全局属性对象、创建全局数据库连接、加载缓存信息等
2.ServeltRequestListener接口
监听HttpServletRequest的创建 销毁
public void requestInitialized(ServletRequestEvent sre)//request创建时调用 public void requestDestroyed(ServletRequestEvent sre)//request销毁时调用
ServletRequestAttributeListener接口 request域对象值改变
public void attributeAdded(ServletRequestAttributeEvent arg0) { } @Override public void attributeRemoved(ServletRequestAttributeEvent arg0) { } @Override public void attributeReplaced(ServletRequestAttributeEvent arg0) { }
主要用途:读取request参数,记录访问历史
3.HttpSessionListener,HttpSessionAttributeListener
用于监听HttpSession的创建 销毁 或者属性改变
public void sessionCreated(HttpSessionEvent se)//session创建时调用 public void sessionDestroyed(HttpSessionEvent se)//session销毁时调用 public void attributeAdded(HttpSessionBindingEvent arg0) { } public void attributeRemoved(HttpSessionBindingEvent arg0) { } public void attributeReplaced(HttpSessionBindingEvent arg0) { }
主要用途:统计在线人数、记录访问日志等
最后再来讲讲 HttpSessionAcivationListener,HttpSessionBindingListener :
监听绑定到HttpSeesion域中的某个对象的状态的事件监听器(创建普通JavaBean)
HttpSessionBingingListener:当实现此接口的对象被加入HttpSession或从中移除时,就会调用对应的valueBound()与valueUnbound()方法,并传入HttpSessionBindingEvent对象,可以通过该对象的getSession()取得HttpSession对象。
HttpSessionAcivationListener: 可以实现对象的钝化和活化 >具体的可以自己百度,因为用的比较少,这里不再详细介绍.
钝化: 将session对象持久化到存储设备上
活化: 将session对象从存储设备上进行恢复
ps:使用注解 @WebListener无法去定义监听器的执行顺序
三. Spring 监听器源码简单分析
在使用spirng,springmvc的web项目中 我们常用的监听器有两个<context-param> <param-name>contextConfigLocation</param-name> <param-value> classpath*:spring/applicationContext-*.xml classpath*:spring/dataSource.xml </param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <listener> <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class> </listener>
ContextLoaderListener 能够监听ServletContext对象的生命周期,实际上就是监听Web应用的生命周期。当Servlet容器启动或终止Web应用时,会触发ServletContextEvent事件,该事件由ServletContextListener来处理。在ServletContextListener接口中定义了处理ServletContextEvent 事件的两个方法contextInitialized()和contextDestroyed()。
ContextLoaderListener监听器的作用就是启动Web容器时,自动装配ApplicationContext的配置信息。因为它实现了ServletContextListener这个接口,在web.xml配置了这个监听器,启动容器时,就会默认执行它实现的方法。由于在ContextLoaderListener中关联了ContextLoader这个类,所以整个加载配置过程由ContextLoader来完成。
public class ContextLoaderListener extends ContextLoader implements ServletContextListener { public ContextLoaderListener() { } public ContextLoaderListener(WebApplicationContext context) { super(context); } @Override public void contextInitialized(ServletContextEvent event) { initWebApplicationContext(event.getServletContext()); } @Override public void contextDestroyed(ServletContextEvent event) { closeWebApplicationContext(event.getServletContext()); ContextCleanupListener.cleanupAttributes(event.getServletContext()); } }
接下来看父类
//看名字就知道是拿到当前的上下文对象 private static volatile WebApplicationContext currentContext; //初始化保存的context对象 private WebApplicationContext context; //静态代码块 加载配置文件里的信息 static { try { ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, ContextLoader.class); defaultStrategies = PropertiesLoaderUtils.loadProperties(resource); } catch (IOException ex) { throw new IllegalStateException("Could not load 'ContextLoader.properties': " + ex.getMessage()); } } public WebApplicationContext initWebApplicationContext(ServletContext servletContext) { if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) { throw new IllegalStateException( "Cannot initialize context because there is already a root application context present - " + "check whether you have multiple ContextLoader* definitions in your web.xml!"); } Log logger = LogFactory.getLog(ContextLoader.class); servletContext.log("Initializing Spring root WebApplicationContext"); if (logger.isInfoEnabled()) { logger.info("Root WebApplicationContext: initialization started"); } long startTime = System.currentTimeMillis(); try { if (this.context == null) { //通过反射创建上下文实例 this.context = createWebApplicationContext(servletContext); } if (this.context instanceof ConfigurableWebApplicationContext) { ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context; if (!cwac.isActive()) { if (cwac.getParent() == null) { ApplicationContext parent = loadParentContext(servletContext); cwac.setParent(parent); } //配置 并刷新WebApplicationContext configureAndRefreshWebApplicationContext(cwac, servletContext); } } servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context); ClassLoader ccl = Thread.currentThread().getContextClassLoader(); if (ccl == ContextLoader.class.getClassLoader()) { currentContext = this.context; } else if (ccl != null) { currentContextPerThread.put(ccl, this.context); } if (logger.isDebugEnabled()) { logger.debug("Published root WebApplicationContext as ServletContext attribute with name [" + WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + "]"); } if (logger.isInfoEnabled()) { long elapsedTime = System.currentTimeMillis() - startTime; logger.info("Root WebApplicationContext: initialization completed in " + elapsedTime + " ms"); } return this.context; } catch (RuntimeException ex) { logger.error("Context initialization failed", ex); servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex); throw ex; } catch (Error err) { logger.error("Context initialization failed", err); servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, err); throw err; } }
这段代码最主要的是在这里
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
key为 :String ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE = WebApplicationContext.class.getName() + ".ROOT";
value为: this.context
在程序启动的时候 我们debug看看里面保存了什么
发现了一个很熟悉的名字
beanFactory ,这不就是spring的bean工厂类嘛!!
我们可以实现一个接口 用来手动拿取spring容器里面的bean
@Component public class SpringApplicationContextHolder implements ApplicationContextAware { private static ApplicationContext context; @Override public void setApplicationContext(ApplicationContext context) throws BeansException { SpringApplicationContextHolder.context = context; } public static Object getSpringBean(String beanName) { Validate.notEmpty(beanName, "bean name is required"); return context==null?null:context.getBean(beanName); } public static String[] getBeanDefinitionNames() { return context.getBeanDefinitionNames(); } }
具体可以应用在多线程中,spring为了安全 不允许在多线程中用注解来注入类,我们可以用上面的代码来实现注入.
Reference:
http://www.cnblogs.com/sherryueda/p/4273169.htmlhttp://blog.csdn.net/lihuapiao/article/details/51919283
相关文章推荐
- spring心得2--bean的生命周期@Spring监听器的作用@Spring初始化容器案例分析@web项目使用
- spring心得2--bean的生命周期@Spring监听器的作用@Spring初始化容器案例分析@web项目使用
- spring心得2--bean的生命周期@Spring监听器的作用@Spring初始化容器案例分析@web项目使用
- 关于oracle11g RAC 监听器使用中出现的no services以及no listener分析
- spring aop(十)--spring security启用全局方法使用aop的分析
- spring心得10--使用Aspectj进行AOP开发介绍及案例分析
- spring心得10--使用Aspectj进行AOP开发介绍及案例分析
- spring map使用annotation泛型注入问题分析
- Spring源码分析【6】-ThreadLocal的使用和源码分析
- Listener 监听器&&Spring使用Log4jConfigListener配置Log4j日志
- 自定义Servlet监听器中使用Spring提供Bean的方法
- Spring Boot下Druid连接池的使用配置分析
- 使用clone解决hibernate+spring集成中的延迟加载问题及分析(no session or session was closed)
- 使用 Spring、Elasticsearch 及 Logstash 构建企业级数据搜索和分析平台
- spring websocket源码分析续Handler的使用
- 使用 Spring、Elasticsearch 及 Logstash 构建企业级数据搜索和分析平台
- spring map使用annotation泛型注入问题分析
- Spring对Quartz的封装实现简单分析及使用注意事项
- Spring源码分析-AOP拦截器链的使用(六)
- 使用spring整合mybatis时,sqlMapConfig.xml的分析