一、简介:

ApplicationContext事件机制是观察者设计模式的实现。

Spring 的事件处理是单线程的,所以如果一个事件被发布,直至并且除非所有的接收者得到的该消息,该进程被阻塞并且流程将不会继续。因此,如果事件处理被使用,在设计应用程序时应注意。

Spring中有一些内置的事件如下

容器事件(ApplicationContextEvent):
ContextRefresheEvent:
    ApplicationContext容器初始化或刷新时触发该事件。此处的初始化是指:所有的Bean被成功装载,后处理Bean被检测并激活,所有Singleton Bean 被预实例化,ApplicationContext容器已就绪可用
ContextStartedEvent:
    当spring启动时,或者说是context调用start()方法时,会触发此事件
ContextStoppedEvent:
    当spring停止时,或者说context调用stop()方法时,会触发此事件
ContextClosedEvent:
    当spring关闭时,或者说context调用close()方法时,会触发此事件

Web应用相关(RequestHandledEvent):
ServletRequestHandledEvent:
    每次请求处理结束后,容器上下文都发布了一个ServletRequestHandledEvent事件

二、自定义事件和事件监听器

步骤

1.自定义事件:扩展ApplicationEvent类,需要有构造函数。

2.自定义事件监听器:实现ApplicationListener接口,重写onApplicationEvent方法,该方法处理监听到某个时间后做哪些操作。

3.通过ApplicationContext发布事件

代码演示

自定义事件

msg为发布事件时需要给监听器传递的参数

package com.sid.util.event;

import org.springframework.context.ApplicationEvent;

/**
 * @program: springboot
 * @description: 自定义容器事件类
 * @author: Sid
 * @date: 2018-11-21 10:42
 * @since: 1.0
 **/
public class MyApplicationEvent  extends ApplicationEvent {

    private String msg;

    public MyApplicationEvent(Object source, String msg) {
        super(source);
        this.msg = msg;
    }

    /**
     * Create a new ApplicationEvent.
     *
     * @param source the object on which the event initially occurred (never {@code null})
     */
    public MyApplicationEvent(Object source) {
        super(source);
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }
}

自定义事件监听器

onApplicationEvent()方法入参介绍

如果入参是ApplicationEvent,则每当容器内发生任何事件时,此方法都会被触发

如果入参是MyApplicationEvent,则只有容器内发生MyApplicationEvent事件时,此方法才会被触发

package com.sid.util.event;

import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;

/**
 * @program: springboot
 * @description: 自定义事件监听器 第一种方式  实现ApplicationListener接口
 * @author: Sid
 * @date: 2018-11-21 10:43
 * @since: 1.0
 **/
@Component
public class MyApplicationListener implements ApplicationListener {


    @Override
    //参数的范围越广泛,监听到的事件越多
    //如果入参是ApplicationEvent,则每当容器内发生任何事件时,此方法都会被触发
    //如果入参是MyApplicationEvent,则只有容器内发生如果入参是MyApplicationEvent事件时,此方法才会被触发
    //之前做的某个功能,起了很多线程,就是因为入参范围太广泛了,触发了很多次
    public void onApplicationEvent(ApplicationEvent event) {
        System.out.println(event.getClass().getName() + "被监听......");
        if(event instanceof MyApplicationEvent){
            MyApplicationEvent myApplicationEvent = (MyApplicationEvent) event;
            System.out.println("MyApplicationEvent.msg is :"+(myApplicationEvent.getMsg()));
        }
    }
}

/**
 * @program: springboot
 * @description: 自定义事件监听器 第二种方式
 * 写一个带参的方法,参数为需要监听的事件的父类或需要监听的事件
 * 使用@EventListener
 * @author: Sid
 * @date: 2018-11-21 10:43
 * @since: 1.0
 *
@Component
public class MyApplicationListener  {


    //参数的范围越广泛,监听到的事件越多
    //如果入参是ApplicationEvent,则每当容器内发生任何事件时,此方法都会被触发
    //如果入参是MyApplicationEvent,则只有容器内发生如果入参是MyApplicationEvent事件时,此方法才会被触发
    //之前做的“排队导出”,同事换了包过后,起了很多线程,就是因为入参范围太广泛了,触发了很多次
    @EventListener
    public void onApplicationEvent(ApplicationEvent event) {
        System.out.println(event.getClass().getName() + "被监听......");
        if(event instanceof MyApplicationEvent){
            MyApplicationEvent myApplicationEvent = (MyApplicationEvent) event;
            System.out.println("MyApplicationEvent.msg is :"+(myApplicationEvent.getMsg()));
        }
    }
}*/

这里为了在普通类中得到ApplicationContext而不重新加载一次容器,实现了ApplicationContextAware接口

package com.sid.util.event;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

/**
 * @program: springboot
 * @description:
 * @author: Sid
 * @date: 2018-11-21 11:33
 * @since: 1.0
 **/
@Component
public class SpringBootBeanUtil implements ApplicationContextAware {
    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        if (SpringBootBeanUtil.applicationContext == null) {
            SpringBootBeanUtil.applicationContext = applicationContext;
        }
        System.out.println("========ApplicationContext配置成功========");
        System.out.println("========在普通类可以通过调用SpringUtils.getAppContext()获取applicationContext对象========");
        System.out.println("========applicationContext="+ SpringBootBeanUtil.applicationContext +"========");

    }

    /**
     * 获取applicationContext
     * @return
     */
    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    /**
     * 通过name获取 Bean.
     * @param name
     * @return
     */
    public static Object getBean(String name) {
        return getApplicationContext().getBean(name);
    }

    /**
     * 通过class获取Bean.
     * @param clazz
     * @return
     */
    public static <T> T getBean(Class<T> clazz) {
        return getApplicationContext().getBean(clazz);
    }

    /**
     * 通过name,以及Clazz返回指定的Bean
     * @param name
     * @param clazz
     * @return
     */
    public static <T> T getBean(String name, Class<T> clazz) {
        return getApplicationContext().getBean(name, clazz);
    }
}

发布事件

package com.sid.controller;

import com.sid.util.event.MyApplicationEvent;
import com.sid.util.event.SpringBootBeanUtil;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * @program: springboot
 * @description:
 * @author: Sid
 * @date: 2018-11-21 10:59
 * @since: 1.0
 **/
@Controller
public class EventController {

    @ResponseBody
    @RequestMapping(value = "/myApplicationEvent")
    public String testEvent()
    {
        ApplicationContext context = SpringBootBeanUtil.getApplicationContext();
        //发布事件
        context.publishEvent(new MyApplicationEvent(new Object(),"sid"));
        return "test EventController testEvent ";
    }
}

测试结果

org.springframework.context.event.ContextRefreshedEvent被监听......
2018-11-21 12:23:05.082 INFO [main]org.apache.coyote.http11.Http11NioProtocol.log:179 -Initializing ProtocolHandler ["http-nio-8088"]
2018-11-21 12:23:05.082 INFO [main]org.apache.coyote.http11.Http11NioProtocol.log:179 -Starting ProtocolHandler ["http-nio-8088"]
2018-11-21 12:23:05.083 INFO [main]org.apache.tomcat.util.net.NioSelectorPool.log:179 -Using a shared selector for servlet write/read
2018-11-21 12:23:05.086 INFO [main]org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainer.start:201 -Tomcat started on port(s): 8088 (http)
org.springframework.boot.context.embedded.EmbeddedServletContainerInitializedEvent被监听......
org.springframework.boot.context.event.ApplicationReadyEvent被监听......

com.sid.util.event.MyApplicationEvent被监听......
MyApplicationEvent.msg is :sid

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐