SpringBoot之配置监听器

  • A+
所属分类:Java片段

监听器简介

listener是servlet规范中定义的一种特殊类。用于监听servletContext、HttpSession和servletRequest等域对象的创建和销毁事件。监听域对象的属性发生修改的事件。用于在事件发生前、发生后做一些必要的处理。其主要可用于以下方面:1、统计在线人数和在线用户2、系统启动时加载初始化信息3、统计网站访问量4、记录用户访问路径

监听器的使用

监听器也叫Listener,是servlet的监听器,可以用于监听Web应用中某些对象,信息的创建,销毁,增加,修改,删除等动作的发生,然后做出相应的响应处理。当范围对象的状态发生变化时,服务器自动调用监听器对象中的方法,常用于统计在线人数和在线用户,系统加载时进行信息初始化,统计网站的访问量等。

ServletContextListener

用于监听servletContext对象的创建以及销毁

在 Servlet 中有一个 ServletContextListener 接口,它能够监听 ServletContext 对象的生命周期,实际上就是监听 Web 应用的生命周期。

当Servlet 容器启动或终止Web 应用时,会触发ServletContextEvent 事件,该事件由 ServletContextListener 来处理。在 ServletContextListener 接口中定义了处理ServletContextEvent 事件的两个方法。

/**
 * @Description TODO
 * 微信公众号:云说Java、Java栈记
 * @Date 2021/3/2 22:18
 * @Created by moyun
 */
@Component
public class MyServletContextListener implements ServletContextListener {

    private static final Logger logger = LoggerFactory.getLogger(MyServletContextListener.class);

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        logger.info("容器即将初始化...");
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        logger.info("容器初即将销毁...");
    }
}

contextInitialized(ServletContextEvent sce) :当Servlet 容器启动Web 应用时调用该方法。在调用完该方法之后,容器再对Filter 初始化,并且对那些在Web 应用启动时就需要被初始化的Servlet 进行初始化。

contextDestroyed(ServletContextEvent sce) :当Servlet 容器终止Web 应用时调用该方法。在调用该方法之前,容器会先销毁所有的Servlet 和Filter 过滤器。

HttpSessionListener

监听session对象的创建以及销毁

监听器还有一个比较常用的地方就是用来监听 session 对象,来获取在线用户数量,现在有很多开发者都有自己的网站,监听 session 来获取当前在下用户数量是个很常见的使用场景,下面来介绍一下如何来使用。

/**
 * @Description 使用HttpSessionListener统计在线用户数的监听器
 * 微信公众号:云说Java、Java栈记
 * @Date 2021/02/14 22:39
 * @Created by 墨云
 */
@Component
public class MyHttpSessionListener implements HttpSessionListener {

    private static final Logger logger = LoggerFactory.getLogger(MyHttpSessionListener.class);

    //记录在线的用户数量
    public Integer count = 0;

    @Override
    public synchronized void sessionCreated(HttpSessionEvent httpSessionEvent) {
        logger.info("新用户上线了");
        count++;
        httpSessionEvent.getSession().getServletContext().setAttribute("count",count);
    }

    @Override
    public synchronized void sessionDestroyed(HttpSessionEvent httpSessionEvent){
        logger.info("用户下线了");
        count--;
        httpSessionEvent.getSession().getServletContext().setAttribute("count",count);
    }
}

需要注意的是,sessionid是一个会话的key,浏览器第一次访问服务器会在服务器端生成一个session,有一个sessionid和它对应。tomcat生成的sessionid叫做jsessionid。

sessionid第一次产生是在直到某server端程序调用 HttpServletRequest.getSession(true)这样的语句时才被创建,才能被监听器监听

/**
 * @Description TODO
 * 微信公众号:云说Java、Java栈记
 * @Date 2021/2/28 23:07
 * @Created by moyun
 */
@RestController
@RequestMapping("/sysUser")
public class SysUserController {

    @RequestMapping("/getUserById/{id}")
    public BaseResponse getUserById(@PathVariable Long id,HttpServletRequest request){
        SysUser user = userService.getById(id);
        System.out.println(request.getSession().getServletContext().getAttribute("count"));
        return BaseResponse.renderSuccess("成功!",user);
    }
}

ServletRequestListener

监听request对象的创建以及销毁

MyServletRequestListener类实现了ServletRequestListener接口,因此可以对ServletRequest对象的创建和销毁这两个动作进行监听。

用户每一次访问都会创建request对象,当访问结束后,request对象就会销毁。

request对象创建时会执行requestInitialized()方法,在销毁时执行requestDestroyed()方法

/**
 * @Description TODO
 * 微信公众号:云说Java、Java栈记
 * @Date 2021/3/2 22:18
 * @Created by moyun
 */
@Component
public class MyServletRequestListener  implements ServletRequestListener {

    private static final Logger logger = LoggerFactory.getLogger(MyServletRequestListener.class);

    @Override
    public void requestDestroyed(ServletRequestEvent sre) {
         logger.info(sre.getServletRequest() + ":已销毁!");

    }

    @Override
    public void requestInitialized(ServletRequestEvent sre) {
        logger.info(sre.getServletRequest() + ":已创建!");
    }
}

ServletContextAttributeListener

监听servletContext对象中属性的改变

Serv letContextA ttri buteListener 用于监昕ServletContext (application )范围内属性的变化, 实现该按
口的监昕器需要实现如下三个方法

/**
 * @Description TODO
 * 微信公众号:云说Java、Java栈记
 * @Date 2021/3/2 22:18
 * @Created by moyun
 */
@Component
public class MyServletContextAttributeListener implements ServletContextAttributeListener{

    private static final Logger logger = LoggerFactory.getLogger(MyServletContextAttributeListener.class);


    //把一个属性存入application范围时触发该方法
    @Override
    public void attributeAdded(ServletContextAttributeEvent scae) {
        ServletContext application = scae.getServletContext();
        String name = scae.getName();
        Object value = scae.getValue();
        logger.info(application+"范围内添加了name:"+name+",value:"+value);
    }

    //把一个属性从application范围删除时触发该方法
    @Override
    public void attributeRemoved(ServletContextAttributeEvent scae) {
        ServletContext application = scae.getServletContext();
        String name = scae.getName();
        Object value = scae.getValue();
        logger.info(application+"范围内的name:"+name+",value:"+value+"被删除了");
    }

    //替换application范围内的属性时触发该方法
    @Override
    public void attributeReplaced(ServletContextAttributeEvent scae) {
        ServletContext application = scae.getServletContext();
        String name = scae.getName();
        Object value = scae.getValue();
        logger.info(application+"范围内的name:"+name+",value:"+value+"被更改了");
    }
}

触发机制如下:

@RequestMapping("/getUserById/{id}")
public BaseResponse getUserById(@PathVariable Long id,HttpServletRequest request){
    SysUser user = userService.getById(id);
    request.getServletContext().setAttribute("user",user);
    request.getServletContext().setAttribute("user","user");
    request.getServletContext().removeAttribute("user");
    return BaseResponse.renderSuccess("成功!",user);
}

HttpSessionAttributeListener

监听session对象中属性的改变

/**
 * @Description TODO
 * 微信公众号:云说Java、Java栈记
 * @Date 2021/3/2 22:18
 * @Created by moyun
 */
@Component
public class MyHttpSessionAttributeListener implements HttpSessionAttributeListener {

    private static final Logger logger = LoggerFactory.getLogger(MyHttpSessionAttributeListener.class);


    //Session添加属性时执行
    @Override
    public void attributeAdded(HttpSessionBindingEvent se) {
        logger.info(se.getSession().getId()+"新增了某个属性!");
    }

    //Session删除属性时执行
    @Override
    public void attributeRemoved(HttpSessionBindingEvent se) {
        logger.info(se.getSession().getId()+"删除了某个属性!");
    }

    //Session修改属性时执行
    @Override
    public void attributeReplaced(HttpSessionBindingEvent se) {
        logger.info(se.getSession().getId()+"修改了某个属性!");
    }
}

触发机制:

    @RequestMapping("/getUserById/{id}")
    public BaseResponse getUserById(@PathVariable Long id,HttpServletRequest request){
        SysUser user = userService.getById(id);
        request.getSession().setAttribute("user",user);
        request.getSession().setAttribute("user","user");
        request.getSession().removeAttribute("user");
        return BaseResponse.renderSuccess("成功!",user);
    }

ServletRequestAttributeListener

监听request对象中属性的改变

/**
 * @Description TODO
 * 微信公众号:云说Java、Java栈记
 * @Date 2021/3/2 22:18
 * @Created by moyun
 */
@Component
public class MyServletRequestAttributeListener implements ServletRequestAttributeListener {

    private static final Logger logger = LoggerFactory.getLogger(MyServletRequestAttributeListener.class);

    //request对象属性新增时执行
    @Override
    public void attributeAdded(ServletRequestAttributeEvent srae) {
        logger.info("request对象新增属性:"+srae.getName());
    }

    //request对象属性删除时执行
    @Override
    public void attributeRemoved(ServletRequestAttributeEvent srae) {
        logger.info("request对象删除属性:"+srae.getName());
    }

    //request对象属性修改时执行
    @Override
    public void attributeReplaced(ServletRequestAttributeEvent srae) {
        logger.info("request对象修改属性:{},值变量为:{}",srae.getName(),srae.getValue());
    }
}

触发机制:

@RequestMapping("/getUserById/{id}")
public BaseResponse getUserById(@PathVariable Long id,HttpServletRequest request){
    SysUser user = userService.getById(id);
    request.setAttribute("user",user);
    request.setAttribute("user","user");
    request.removeAttribute("user");
    return BaseResponse.renderSuccess("成功!",user);
}

自定义事件监听

在实际项目中,我们往往需要自定义一些事件和监听器来满足业务场景,比如在微服务中会有这样的场景:微服务 A 在处理完某个逻辑之后,需要通知微服务 B 去处理另一个逻辑,或者微服务 A 处理完某个逻辑之后,需要将数据同步到微服务 B,这种场景非常普遍,这个时候,我们可以自定义事件以及监听器来监听,一旦监听到微服务 A 中的某事件发生,就去通知微服务 B 处理对应的逻辑。

自定义事件

自定义事件需要继承 ApplicationEvent 对象,在事件中定义一个 User 对象来模拟数据,构造方法中将User 对象传进来初始化。如下:

/**
 * @Description TODO
 * 微信公众号:云说Java、Java栈记
 * @Date 2021/02/14 22:39
 * @Created by 墨云
 */
public class MyEvent extends ApplicationEvent {

    private User user;

    public MyEvent(Object source, User user) {
        super(source);
        this.user = user;
    }
    // 省去get、set方法
}

自定义监听器

接下来,自定义一个监听器来监听上面定义的 MyEvent 事件,自定义监听器需要实现ApplicationListener 接口即可。如下

/**
 * @Description 自定义监听器,监听MyEvent事件
 * 微信公众号:云说Java、Java栈记
 * @Date 2021/02/14 22:39
 * @Created by 墨云
 */
@Component
public class MyEventListener implements ApplicationListener<MyEvent> {

    @Override
    public void onApplicationEvent(MyEvent myEvent) {
        // 把事件中的信息获取到
        User user = myEvent.getUser();
        // 处理事件,实际项目中可以通知别的微服务或者处理其他逻辑等等
        System.out.println("用户名:" + user.getUsername());
        System.out.println("密码:" + user.getPassword());
    }
}

然后重写 onApplicationEvent 方法,将自定义的 MyEvent 事件传进来,因为该事件中,我们定义了User 对象(该对象在实际中就是需要处理的数据,在下文来模拟),然后就可以使用该对象的信息了。OK,定义好了事件和监听器之后,需要手动发布事件,这样监听器才能监听到,这需要根据实际业务场景来触发,针对本文的例子,我写个触发逻辑,如下:

/**
 * @Description TODO
 * 微信公众号:云说Java、Java栈记
 * @Date 2021/02/14 22:39
 * @Created by 墨云
 */
@Service
public class UserService {
    @Resource
    private ApplicationContext applicationContext;

    public User getUser2() {
        User user = new User(1L, "墨云", "123456");
        // 发布事件
        MyEvent event = new MyEvent(this, user);
        applicationContext.publishEvent(event);
        return user;
    }
}

在 service 中注入 ApplicationContext,在业务代码处理完之后,通过 ApplicationContext 对象手动发布 MyEvent 事件,这样我们自定义的监听器就能监听到,然后处理监听器中写好的业务逻辑。最后,在 Controller 中写一个接口来测试一下:

@GetMapping("/request")
public String getRequestInfo(HttpServletRequest request) {
    System.out.println("requestListener中的初始化的name数据:" + request.getAttribute("name"));
    return "success";
}

在浏览器中输入 http://localhost:8080/listener/publish ,然后观察一下控制台打印的用户名和密码,即可说明自定义监听器已经生效。

  • 云说Java
  • 关注公众号获取更多资源
  • weinxin
  • Java栈记
  • 关注公众号获取更多资源
  • weinxin
墨云

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: