前言
监听器(Listener)就是监听对象的创建、销毁等状态的变化以及定义一些事件发生后接下来要进行的动作;主要监听的三个域对象为:ServletRequest域、HttpSession域 和ServletContext域
在目前的Servlet API中提供的web事件监听器接口有如下所示的几个:
1.ServletContextListener -- 监听servletContext对象的创建以及销毁
1.1 contextInitialized(ServletContextEvent arg0) -- 创建时执行
1.2 contextDestroyed(ServletContextEvent arg0) -- 销毁时执行
2.HttpSessionListener -- 监听session对象的创建以及销毁
2.2 sessionCreated(HttpSessionEvent se) -- 创建时执行
2.2 sessionDestroyed(HttpSessionEvent se) -- 销毁时执行
3.ServletRequestListener -- 监听request对象的创建以及销毁
3.1 requestInitialized(ServletRequestEvent sre) -- 创建时执行
3.2 requestDestroyed(ServletRequestEvent sre) -- 销毁时执行
4.ServletContextAttributeListener -- 监听servletContext对象中属性的改变
4.1 attributeAdded(ServletContextAttributeEvent event) -- 添加属性时执行
4.2 attributeReplaced(ServletContextAttributeEvent event) -- 修改属性时执行
4.3 attributeRemoved(ServletContextAttributeEvent event) -- 删除属性时执行
5.HttpSessionAttributeListener --监听session对象中属性的改变
5.1 attributeAdded(HttpSessionBindingEvent event) -- 添加属性时执行
5.2 attributeReplaced(HttpSessionBindingEvent event) -- 修改属性时执行
5.3 attributeRemoved(HttpSessionBindingEvent event) -- 删除属性时执行
6.ServletRequestAttributeListener --监听request对象中属性的改变
6.1 attributeAdded(ServletRequestAttributeEvent srae) -- 添加属性时执行
6.2 attributeReplaced(ServletRequestAttributeEvent srae) -- 修改属性时执行
6.3 attributeRemoved(ServletRequestAttributeEvent srae) -- 删除属性时执行
参考文章:
1、spring boot入门(八) springboot的监听器Listener。最完整、简单易懂、详细的spring boot教程。 2、Java Web Listener学习笔记 3、Java篇-Listener
1、Listener接口的实现及使用
两步操作即可以实现监听器接口的实现:
- 自定义一个实现相关Listener接口的类
- 在启动类中进行相关的容器配置
1.1、ServletContextListener接口的实现
package com.learn.listeners;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@WebListener
public class ContextListener implements ServletContextListener{
private static final Logger logger=LoggerFactory.getLogger(ContextListener.class);
@Override
public void contextInitialized(ServletContextEvent sce) {
logger.info("初始化一个servletContext......");
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
logger.info("销毁一个servletContext......");
}
}
配置监听器的容器,有两种方式:
(1)如上述代码中所示,在定义的监听器类上使用 @WebListener 注解,然后在项目的启动类中,加上如下所示内容:
@SpringBootApplication
@ServletComponentScan(basePackages= {"com.learn.listeners"}) // 添加监听器所在的包名
public class LearnSpringbootIpApplication {
.......
}
(2)在项目的启动类中,使用ServletListenerRegistrationBean来创建Bean,如下所示:
@Bean
public ServletListenerRegistrationBean<ContextListener> contextListenerBean() {
ServletListenerRegistrationBean<ContextListener> contextListenerBean= new ServletListenerRegistrationBean<ContextListener>();
contextListenerBean.setListener(new ContextListener());
contextListenerBean.setOrder(1);
return contextListenerBean;
}
在启动web项目时,会执行contextInitialized 初始化的方法,当web项目关闭时会执行销毁的方法。日志记录如下:
1.2、HttpSessionListener 接口的实现及使用
实现代码:
package com.learn.listeners;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@WebListener
public class SessionListener implements HttpSessionListener {
private static final Logger logger=LoggerFactory.getLogger(SessionListener.class);
@Override
public void sessionCreated(HttpSessionEvent se) {
logger.info("初始化一个sessionListener......");
}
@Override
public void sessionDestroyed(HttpSessionEvent se) {
logger.info("销毁一个sessionListener......");
}
}
实现完成Session监听器以后,配置过程与1.1中介绍的一样,这里就不赘述了;运行项目,当执行的过程中发生Session的创建或销毁时就会触发监听器中相应的代码。
测试代码:
@CrossOrigin
@RequestMapping(value="/api/v2/session",method=RequestMethod.GET)
public void destorySession(HttpServletRequest request) {
HttpSession session=request.getSession();
session.invalidate();
}
执行结果:
1.3、ServletRequestListener 接口的实现及使用
package com.learn.listeners;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.annotation.WebListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@WebListener
public class RequestListener implements ServletRequestListener {
private static final Logger logger=LoggerFactory.getLogger(RequestListener.class);
@Override
public void requestDestroyed(ServletRequestEvent sre) {
logger.info("初始化一个requestListener......");
}
@Override
public void requestInitialized(ServletRequestEvent sre) {
logger.info("销毁一个requestListener......");
}
}
实现完成Session监听器以后,配置过程与1.1中介绍的一样;当项目中有ServletRequest对象的创建或者销毁时就是触发该监听器。
2、自定义事件的发布及监听
关于这块的内容,在网上看到一个不错的文章,参考文章地址:spring 自定义事件发布及监听(简单实例)流程分析:
在一个完整的事件体系中,除了事件和监听器以外,还应该有3个概念;
- 事件源:事件的产生者,任何一个event都必须有一个事件源;
- 事件广播器:它是事件和事件监听器之间的桥梁,负责把事件通知给事件监听器;
- 事件监听器注册表:就是spring框架为所有的监听器提供了一个存放的地方;
通过流程图,可以看出它们是如何各司其职的,如下:
其实通过流程图,我们很容易发现事件体系就是观察者模式的具体实现,它并没有任何的神秘之处。
结构分析:
1、 事件类(ApplicaitonEvent):目前spring框架本身仅仅提供了几个事件,很多的事件都是需要自定义的。
ApplicationEvent唯一的构造函数是ApplicaitonEvent(Object source),通过source指定事件源。 它有两个子类;
(1)ApplicationContextEvent:容器事件,也就是说事件源是ApplicationContext,框架提供了四个子类,分别代表容器启动,刷新,停止和关闭事件。
(2)RequestHandleEvent:这是一个与Web应用相关的事件,当一个请求被处理后,才会产生该事件。
一般来说,我们都是扩展ApplicationEvent来自定义事件。
2. 事件监听器接口(ApplicationListener)
所有的监听器都需要实现该接口,该接口只定义了一个方法:onApplicaitonEvent (E event),该方法接收事件对象,在该方法中编写事件的响应处理逻辑。
通过一个实例来讲解事件发布和事件监听的过程。这个例子包括一个模拟的邮件发送器MailSender,它在向目的地发送邮件的时候 会产生一个MailSendEvent事件,我们同时向容器中注册了该事件的监听器MailSendListener;
/**
* 继承了ApplicationContextEvent,就是个容器事件
*/
public class MailSendEvent extends ApplicationContextEvent {
private String to; //目的地
public MailSendEvent(ApplicationContext source, String to) {
super(source);
this.to = to;
}
public String getTo(){
return this.to;
}
}
很明显,这里的source是ApplicationContext容器。我们再定义一个该事件的监听器MailSendListener,如下:
@Component
public class MailSendListener implements ApplicationListener<MailSendEvent>{
@Override
public void onApplicationEvent(MailSendEvent mailSendEvent) {
MailSendEvent event = mailSendEvent;
System.out.println("向"+ event.getTo()+ "发送了一封邮件");
}
}
上述提及到所有的监听器都必须要实现ApplicationListener,这里是个泛型类,指定了该监听器只监听MailSendEvent事件。
OK,那我们现在来触发事件:MailSender,也就是事件源:
@Component("mailSender")
public class MailSender {
@Autowired
private ApplicationContext applicationContext; //容器事件由容器触发
public void sendMail(String to){
System.out.println("MailSender开始发送邮件");
MailSendEvent event = new MailSendEvent(applicationContext,to);
applicationContext.publishEvent(event);
}
}
测试代码:
@RestController
public class ListenerController {
@Autowired
private MailSender mailSender;
@CrossOrigin
@RequestMapping(value="/api/v2/listener",method=RequestMethod.GET)
public void testDefinedListener(HttpServletRequest request) {
mailSender.sendMail("北京");
}
}
测试结果: