Spring事件


事件监听处理在代码中为同步的串行执行,不要理解为异步处理,目的只是为了进行
使用ApplicationContext发布事件,ApplicationContext实现了ApplicationEventPublisher接口;
使用ApplicationContextEvent 定义事件,ApplicationContextEvent 继承了ApplicationEvent类;

业务的解耦与代码的解耦

1 简介

在性能要求比较高的接口中,执行一个比较耗时而并不关键的操作(比如上报监控信息什么的),如果同步执行必然是没有意义的,因此一般我们会想去异步处理,通常会使用MQ之类的中间件,不过Spring也提供了事件相关的处理,就是ApplicationEvent,关于这个类这里不再多言,基础的知识可以网上搜索相关教程,不过有一个问题需要注意的是,默认这种事件机制是同步的,好处是如果有事务,发送事件的方法和事件处理的方法在同一个事务里,缺点就是,可能并没有实现我们想象中的异步处理,有一种方案是在处理事件的时候使用一个线程池,通过线程池来异步处理,虽然是解决了异步的问题,但是给笔者一种脱裤子放屁的赶脚,与其这样,还不如直接扔到一个线程池里,何必还走一个事件处理?好在Spring本身也支持ApplicationEvent的异步处理,通过@Async注解就可以了,下面是相关代码:

首先是不使用@Async注解前,ApplicationEvent处理是同步的一个验证

2 例子

2.1 demo1

public abstract class AbstractEvent extends ApplicationEvent {
    public AbstractEvent(Object source) {
        super(source);
    }

    /**
     * 事件执行方法
     */
    public abstract void execute() throws InterruptedException;
}
public class DemoEvent extends AbstractEvent {

    private static final long serialVersionUID = 1L;

    public DemoEvent(Object source) {
        super(source);
    }

    @Override
    public void execute() throws InterruptedException {
        while (true) {
            Thread.sleep(1000);
            System.out.println("======================DemoEvent execute======================" + source);
        }
    }
}
@Component
public class AbstractEventListener implements ApplicationListener<AbstractEvent> {

    @Override
    @Async
    public void onApplicationEvent(AbstractEvent event) {
        try {
            event.execute();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
@RestController
public class IndexController {

    @Autowired
    private ApplicationContext ioc;

    @RequestMapping("/index")
    public void index () {
        System.out.println("===================Java异步执行测试开始===================");
        ioc.publishEvent(new DemoEvent("param"));
        System.out.println("===================Java异步执行测试结束===================");
    }
}

最后开启@EnableAsync
结果如下:
=Java异步执行测试开始=
=Java异步执行测试结束=
DemoEvent executeparam
DemoEvent executeparam
DemoEvent executeparam

2.2 demo2

public class UploadEvent extends ApplicationEvent {
    public UploadEvent(Object source) {
        super(source);
    }
}
@Service
public class TEventListener implements ApplicationListener<UploadEvent> {
    @Override
    public void onApplicationEvent(UploadEvent uploadEvent) {
        try {
            System.out.println(">>>OK1");
            TimeUnit.SECONDS.sleep(5);
            System.out.println(">>>OK2");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
@EnableAsync
@Component
public class SpringContextUtil implements ApplicationContextAware {
	private static ApplicationContext applicationContext; // Spring应用上下文环境
 
	/*
	 * 
	 * 实现了ApplicationContextAware 接口,必须实现该方法;
	 * 
	 * 通过传递applicationContext参数初始化成员变量applicationContext
	 * 
	 */
	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		SpringContextUtil.applicationContext = applicationContext;
	}
 
	public static ApplicationContext getApplicationContext() {
		return applicationContext;
	}
 
	public static<T> T getBean(Class<T> requiredType) {
		return (T) applicationContext.getBean(requiredType);
	}
 
	public static void publishEvent(ApplicationEvent event){
		applicationContext.publishEvent(event);
	}
}
   @Test
    public void testEvent(){
        UploadEvent event = new UploadEvent(this);
        SpringContextUtil.publishEvent(event);
        System.out.println(">>>OK");
    }



    @Async
    @Override
    public void onApplicationEvent(UploadEvent uploadEvent) {
        try {
            System.out.println(">>>OK1");
            TimeUnit.SECONDS.sleep(5);
            System.out.println(">>>OK2");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

3 BeanFactory 和 ApplicationContext

接口 BeanFactory 和 ApplicationContext 都是用来从容器中获取 Spring beans

3.1 ApplicationContext

ApplicationContext(应用上下文):继承BeanFactory接口,简单来说就是Spring中的容器,是Spring的一个更高级的容器。可以用来获取容器中的各种bean组件,注册监听事件,加载资源文件等功能。
ApplicationContext 是 Spring 应用程序中的中央接口,用于向应用程序提供配置信息。它继承了 BeanFactory 接口,所以 ApplicationContext 包含 BeanFactory 的所有功能以及更多功能!它的主要功能是支持大型的业务应用的创建。

与 BeanFactory 懒加载的方式不同,它是预加载,所以,每一个 bean 都在 ApplicationContext 启动之后实例化。
特性:
Bean instantiation/wiring
Bean 的实例化/串联
自动的 BeanPostProcessor 注册
自动的 BeanFactoryPostProcessor 注册
方便的 MessageSource 访问(i18n)
ApplicationEvent 的发布

  1. 国际化(MessageSource)
  2. 访问资源,如URL和文件(ResourceLoader)
对资源文件(如:properties)进行存取操作的功能
ApplicationContext acxt =new ClassPathXmlApplicationContext("/applicationContext.xml");

通过虚拟路径来存取(classpath路径:存放.class等编译后文件的路径)
Resource resource = acxt.getResource(“classpath:messages_en_CN.properties”);

通过绝对路径存取资源文件
Resource resource = acxt.getResource(“file:F:/testwork/MySpring/src/messages_en_CN.properties”);

相对路径读取资源文件
Resource resource = acxt.getResource("/messages_en_CN.properties");
  1. 载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的web层
applicationContext.xml(主文件,包括JDBC配置,hibernate.cfg.xml,与所有的Service与DAO基类)

applicationContext-cache.xml(cache策略,包括hibernate的配置)

applicationContext-jmx.xml(JMX,调试hibernate的cache性能)

applicationContext-security.xml(acegi安全)

applicationContext-transaction.xml(事务)

moduleName-Service.xml

moduleName-dao.xml

< beans>
< import resource=“applicationContext-cache.xml”/>
< /beans>
  1. 消息发送、响应机制(ApplicationEventPublisher)
ApplicationContext事件机制是观察者设计模式的实现,通过ApplicationEvent类和ApplicationListener接口,可以实现ApplicationContext事件处理。 如果容器中有一个ApplicationListener Bean,每当ApplicationContext发布ApplicationEvent时,ApplicationListener Bean将自动被触发。

两个重要成员
ApplicationEvent类:容器事件,必须由ApplicationContext发布;
ApplicationListener接口:监听器,可由容器中的任何监听器Bean担任。

例:
1.1. 定义容器事件 EmailEvent extends ApplicationEvent
1.2. 定义监听器 EmailNotifierListener implements ApplicationListener(容器事件的监听器类必须实现ApplicationListener接口)
1.3. 将监听器注入到spring容器
1.4. 测试:
public static void main(String arg[]){  
    //读取Spring容器的配置文件  
    @SuppressWarnings("resource")  
    ApplicationContext applicationContext=new ClassPathXmlApplicationContext("application.xml");  
    //创建一个事件对象  
    EmailEvent emailEvent = new EmailEvent("hello Spring!", "cxg@126.com", "This is SpringApplicatoinContext test!");  
    //主动触发事件监视机制  
    applicationContext.publishEvent(emailEvent);  
}  
  1. AOP(拦截器)
    一般拦截器都是实现HandlerInterceptor,其中有三个方法preHandle、postHandle、afterCompletion

preHandle:执行controller之前执行
postHandle:执行完controller,return modelAndView之前执行,主要操作modelAndView的值
afterCompletion:controller返回后执行
例:
1.1 注册拦截器,并且确定拦截器拦截哪些URL
1.2. 定义拦截器实现类

3.2 BeanFactory:

是Spring里面最底层的接口,提供了最简单的容器的功能,只提供了实例化对象和拿对象的功能;
BeanFactory 接口:
这是一个用来访问 Spring 容器的 root 接口,要访问 Spring 容器,我们将使用 Spring 依赖注入功能,使用 BeanFactory 接口和它的子接口。
通常情况,BeanFactory 的实现是使用懒加载的方式,这意味着 beans 只有在我们通过 getBean() 方法直接调用它们时才进行实例化。

3.3小结:

ApplicationContext 包含 BeanFactory 的所有特性,通常推荐使用前者。但是也有一些限制情形,比如移动应用内存消耗比较严苛,在那些情景中,使用更轻量级的 BeanFactory 是更合理的。然而,在大多数企业级的应用中,ApplicationContext 是你的首选。

ApplicationContext在启动的时候就把所有的Bean全部实例化。它还可以为Bean配置lazy-init=true来让Bean延迟实例化;

延迟实例化的优点:(BeanFactory)

应用启动的时候占用资源很少;对资源要求较高的应用,比较有优势;
不延迟实例化的优点: (ApplicationContext)

所有的Bean在启动的时候都加载,系统运行的速度快;
在启动的时候所有的Bean都加载了,我们就能在系统启动的时候,尽早的发现系统中的配置问题
建议web应用,在启动的时候就把所有的Bean都加载了。(把费时的操作放到系统启动中完成)

SpringBoot中获取ApplicationContext的三种方式:
一、 直接使用Autowired注入
二、利用 spring4.3 的新特性
在这里插入图片描述
三、实现spring提供的接口 ApplicationContextAware
在这里插入图片描述

4 ApplicationEventPublisher

ApplicationEventPublisher的publishEvent实现异步快速。 首先来一个小demo感受一下spring的自定义异步事件。
1、使用ApplicationEventPublisher的publishEvent来发布事件。如下代码,这里的事件指user
idea工具可以识别是事件,我们可以在idea编辑器中看到前面的标示。点一下即可跳转到监听事件中。

@Autowired
    private ApplicationEventPublisher publisher;

    @GetMapping("test")
    public void register() throws Exception {
        User user=new User();
        user.setName("电脑");
        user.setAge(23);
        publisher.publishEvent(user);
    }
@Component
public class AbstractEventListener implements ApplicationListener<AbstractEvent> {

    @Override
    @Async
    public void onApplicationEvent(AbstractEvent event) {
        try {
            event.execute();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

5 java 事件机制

Java中定义了事件机制的两个顶层类:EventObject ,事件的顶层父类(实现了Serializable接口);

EventListener,定义了监听器的顶层接口

Spring的事件框架有如下两个重要的成员:

ApplicationEvent:容器事件,必须由ApplicationContext发布
ApplicationListener:监听器,可由容器中的任何监听器Bean担任
总的来说spring的事件机制主要包括四个步骤
1.编写ApplicationEvent类的子类,这就是我们的事件类
2.编写监听器类,这个类要实现ApplicationListener接口
3 将监听器配置在Spring的容器中
4.调用ApplicationContext的publishEvent()方法来主动触发一个容器事件,或者spring的一些内置事件发生
下面是applicationcontext事件机制的一个例子

第一条输出为spring的内置事件发生,下面为大家介绍spring的几种内置事件

1.ContextRefreshedEvent:ApplicationContext容器初始化或刷新时触发该事件。此处的初始化是指:所有的Bean被成功装载,后处理Bean被检测并激活,所有Singleton Bean 被预实例化,ApplicationContext容器已就绪可用

2.ContextStartedEvent:当使用ConfigurableApplicationContext(ApplicationContext的子接口)接口的start()方法启动ApplicationContext容器时触发该事件。容器管理声明周期的Bean实例将获得一个指定的启动信号,这在经常需要停止后重新启动的场合比较常见

3.ContextClosedEvent:当使用ConfigurableApplicationContext接口的close()方法关闭ApplicationContext时触发该事件

4.ContextStoppedEvent:当使用ConfigurableApplicationContext接口的stop()方法使ApplicationContext容器停止时触发该事件。此处的停止,意味着容器管理生命周期的Bean实例将获得一个指定的停止信号,被停止的Spring容器可再次调用start()方法重新启动

5.RequestHandledEvent:Web相关事件,只能应用于使用DispatcherServlet的Web应用。在使用Spring作为前端的MVC控制器时,当Spring处理用户请求结束后,系统会自动触发该事件。
我们刚触发的就是ContextRefreshedEvent事件

6 ApplicationContext

如果说BeanFactory是Spring的心脏,那么ApplicationContext就是完整的身躯了。ApplicationContext由BeanFactory派生而来,提供了更多面向实际应用的功能。

(1)ApplicationContext是什么?
ApplicationContext是比BeanFactory更加强大的Spring容器,它既可以创建bean、获取bean、还支持国际化、事件广播、获取资源等BeanFactory不具备的功能。

(2)ApplicationContext所继承的接口
Ⅰ、EnvironmentCapable:ApplicationContext继承了这个接口,表示拥有了获取环境变量的功能,可以通过ApplicationContext获取操作系统环境变量和JVM环境变量。

Ⅱ、ListableBeanFactory:ApplicationContext继承了这个接口,就拥有了获取所有beanNames、判断某个beanName是否存在beanDefinition对象、统计BeanDefinition个数、获取某个类型对应的所有beanNames等功能。

Ⅲ、HierarchicalBeanFactory:ApplicationContext继承了这个接口,就拥有了获取父BeanFactory、判断某个name是否存在bean对象的功能。

Ⅳ、MessageSource:ApplicationContext继承了这个接口,就拥有了国际化功能,比如可以直接利用MessageSource对象获取某个国际化资源(比如不同国家语言所对应的字符)

Ⅴ、ApplicationEventPublisher:ApplicationContext继承了这个接口,就拥有了事件发布功能,可以发布事件,这是ApplicationContext相对于BeanFactory比较突出、常用的功能。

Ⅵ、ResourcePatternResolver:ApplicationContext继承了这个接口,就拥有了加载并获取资源的功能,这里的资源可以是文件,图片等某个URL资源都可以。

Spring的事件框架有如下两个重要的成员:

ApplicationEvent:容器事件,必须由ApplicationContext发布;
ApplicationListener:监听器,可由容器中的任何监听器Bean担任;
实际上,Spring的事件机制与所有时间机制都基本相似,它们都需要事件源、事件和事件监听器组成。只是此处的事件源是ApplicationContext,

且事件必须由Java程序显式触发。下面的程序将演示Spring容器的事件机制。程序先定义了一个ApplicationEvent类,其对象就是一个Spring

注意:如果Bean想发布事件,则Bean必须获得其容器的引用。如果程序中没有直接获取容器的引用,则应该让Bean实现

ApplicationContextAware或者BeanFactoryAware接口,从而可以获得容器的引用。
Spring提供如下几个内置事件:

ContextRefreshedEvent:ApplicationContext容器初始化或刷新时触发该事件。此处的初始化是指:所有的Bean被成功装载,
后处理Bean被检测并激活,所有Singleton Bean 被预实例化,ApplicationContext容器已就绪可用
ContextStartedEvent:当使用ConfigurableApplicationContext(ApplicationContext的子接口)接口的start()方法启动ApplicationContext容器时
触发该事件。容器管理声明周期的Bean实例将获得一个指定的启动信号,这在经常需要停止后重新启动的场合比较常见
ContextClosedEvent:当使用ConfigurableApplicationContext接口的close()方法
关闭ApplicationContext时触发该事件
ContextStoppedEvent:当使用ConfigurableApplicationContext接口的stop()方法
使ApplicationContext容器停止时触发该事件。此处的停止,意味着容器管理生命周期的Bean实例将获得一个指定的停止信号,被停止的
Spring容器可再次调用start()方法重新启动
RequestHandledEvent:Web相关事件,只能应用于使用DispatcherServlet的Web应
用。在使用Spring作为前端的MVC控制器时,当Spring处理用户请求结束后,系统会自动触发该事件。

7 spring事件发布

7.1 ApplicationEventPublisher

1)需要自定义一个事件类继承ApplicationEvent;
2)需要自定义一个监听器类实现ApplicationListener接口,或普通类的方法中使用@EventListener注解;
3)使用默认发布器ApplicationEventPublisher发布即可;
4)事件类不需要注入到IOC;监听器需要注入到IOC;ApplicationEventPublisher用Autowired注入进来即可;
5)默认情况下,事件发布与执行是同步的,事件执行完毕,发布者才会执行下面的逻辑;

  1. 自定义一个事件类继承ApplicationEvent
public class MyEvent<T> extends ApplicationEvent {

    private Task task;

    public MyEvent(Task task) {
        super(task);
        this.task = task;
    }

    public Task getTask() {
        return task;
    }
}
  1. Model
@Data
class Task {
    private Long id;
    private String taskName;
    private String taskContext;
    private boolean finish;
}
  1. 自定义一个监听器类实现ApplicationListener接口,或普通类的方法中使用@EventListener注解;
/**
 * 事件监听类
 * 事件的监听器需要实现org.springframework.context.ApplicationListener,并且需要注入到容器之中。
 */
@Component
@Slf4j
class MyEventListenerA implements ApplicationListener<MyEvent> {
    /**
     * 监听方式1:实现ApplicationListener接口,重写onApplicationEvent方法
     * 需要使用Component注入IOC
     */
    @SneakyThrows
    @Async
    @Override
    public void onApplicationEvent(MyEvent MyEvent) {
        Thread.sleep(5000);
        if (Objects.isNull(MyEvent)) {
            return;
        }
        Task task = MyEvent.getTask();
        log.info("监听器A接收任务:{}", JSON.toJSONString(task));
        task.setFinish(true);
        log.info("监听器A此时完成任务");

    }
}
@Component
@Slf4j
class MyEventListenerB implements ApplicationListener<MyEvent> {
    /**
     * 监听方式2:接口和注解混合使用
     * 但此时 @EventListener不能与注解@Async在同一个类中使用,会报错,至于为什么,不知道;
     * 需要使用Component注入IOC
     */
    //@Async//加上这个,@EventListener的方法就会报java.lang.IllegalStateException: Failed to load ApplicationContext
    @SneakyThrows
    @Override
    public void onApplicationEvent(MyEvent MyEvent) {
        Thread.sleep(1000);
        if (Objects.isNull(MyEvent)) {
            return;
        }
        Task task = MyEvent.getTask();
        log.info("监听器B接收任务:{}", JSON.toJSONString(task));
        task.setFinish(true);
        log.info("监听器B此时完成任务");
    }

    @EventListener
    public void someMethod(MyEvent event) throws InterruptedException {
        Thread.sleep(1000);
        log.info("监听器@EventListenerB收到={}", event.getTask());
    }
}
@Component
@Slf4j
class MyEventListennerC {
    /**
     * 监听方式3:注解@EventListener的监听器不需要实现任何接口
     * 需要使用Component注入IOC
     */
    @EventListener
    public void someMethod(MyEvent event) throws InterruptedException {
        Thread.sleep(1000);
        log.info("监听器@EventListenerC收到={}", event.getTask());
    }
}
@Slf4j
@EnableAsync
@Controller
public class PublishEventDemo {
    /**
     * 事件机制:
     * 需要自定义一个事件类继承ApplicationEvent;
     * 需要自定义一个监听器类实现ApplicationListener接口,或普通类的方法中使用@EventListener注解;
     * 使用默认发布器ApplicationEventPublisher发布即可;
     * 事件类不需要注入到IOC;监听器需要注入到IOC;ApplicationEventPublisher用Autowired注入进来即可;
     */


    /**
     * 事件发布器
     */
    @Autowired
    private ApplicationEventPublisher eventPublisher;

    /**
     * 测试类
     */
    @GetMapping("/")
    public void publishTest() throws InterruptedException {
        Task task = new Task();
        task.setId(1L);
        task.setTaskName("测试任务");
        task.setTaskContext("任务内容");
        task.setFinish(false);
        MyEvent event = new MyEvent(task);
        log.info("开始发布任务");
        eventPublisher.publishEvent(event);
        //applicationContext.publishEvent(event);
        log.info("结束发布任务");
        Thread.sleep(10000);
    }
}

事件发送后,会等待事件执行完毕,因此他们是同步的。若想异步执行事件,可以把@Async加到监听方法上;

7.2 ApplicationContext

使用ApplicationContext发布事件,ApplicationContext实现了ApplicationEventPublisher接口;
使用ApplicationContextEvent 定义事件,ApplicationContextEvent 继承了ApplicationEvent类;

/**
 * 事件类
 *
 * @param <T>
 */
@ToString
class MyEvent2<T> extends ApplicationContextEvent {
    private T data;

    public MyEvent2(ApplicationContext source) {
        super(source);
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }
}
/**
 * 监听器类
 */
@Slf4j
@Component
class MyEventListener2 implements ApplicationListener<MyEvent2> {
    @Override
    public void onApplicationEvent(MyEvent2 event) {
        log.info("监听器MyEventListener2收到={}", event);
    }

    @EventListener
    public void someMethod(MyEvent2 event) {
        log.info("监听器MyEventListener2@EventListener收到={}", event);
    }
}

/**
 * 监听器类
 */
@Slf4j
@Component
class MyEventListenner1 {
    @EventListener
    public void someMethod(MyEvent2 event) {
        log.info("监听器MyEventListenner1收到={}", event);
    }
}
@RestController
@Slf4j
public class PublishEventDemo2 {
    /**
     * 使用ApplicationContext发布事件
     */
    @Autowired
    ApplicationContext applicationContext;

    @GetMapping("/")
    public void send() {
        MyEvent2 myEvent2 = new MyEvent2(applicationContext);
        myEvent2.setData("数据");
        log.info("开始发送事件");
        applicationContext.publishEvent(myEvent2);
        log.info("结束发送事件");
    }
}

事件发送后,会等待事件执行完毕,因此他们是同步的。若想异步执行事件,可以把@Async加到监听方法上;

7.3 ApplicationContextAware

核心为 ApplicationContext 对象 以及 实现 ApplicationContextAware 接口

@Component
public class SpringContextBean implements ApplicationContextAware {
 
    private static ApplicationContext applicationContext = null;
 
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        if(SpringContextBean.applicationContext == null){
            SpringContextBean.applicationContext  = applicationContext;
        }
    }
 
    /** 获取applicationContext */
    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }
}
SpringContextBean.getApplicationContext().publishEvent(new DisburseSuccessEvent(this, disbursement));

7.4 Spring中的观察者模式

发布的事件,Event,ApplicationEvent是一个抽象类继承了EventObject,EventObject是JDK中的类,所有的事件类都建议继承自EventObject。

public abstract class ApplicationEvent extends EventObject{}

事件监听器,ApplicationListener是一个接口,该接口继承了EventListener接口。EventListener接口是JDK中的接口,所有的事件监听器都建议继承EventListener接口。

@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {}

事件发布,ApplicationEventPublisher,ApplicationContext继承该接口,并在抽象实现类AbstractApplicationContext中做了实现。

applicationContext.publishEvent(new FileParseEvent(this, streamBean));

AbstractApplicationContext类中publishEvent方法实现:

Spring 中也对Java中事件机制做了很多的扩展和衍生,提供了很多方便的接口和类。

对事件的定义如下:

ApplicationEvevnt:继承 EventObject 类,自定义事件源应该继承该类

ApplicationEventListener:继承EventListener接口,自定义监听者可以通过实现该接口

ApplicationEventPublisher :封装了事件发布的方法,通知所有在 Spring 中注册的监听者进行处理

基于Spring提供的基类,可以进行自定义各类符合业务和流程的事件;自定义的监听者实现类,可以由 Spring 容器进行管理,只需要通过 ApplicationEventPublisher 进行发布进行,不用自己去实现监听者的注册、通知等等过程。

// 监听 UserRegisterEvent事件
@Component
@Slf4j
@Order(0)
public class RegisterListener implements ApplicationListener<UserRegisterEvent> {
    

    /**
     * 使用接口实现的方式来监听事件
     *
     * @param event 用户注册事件
     */
    @Override
    public void onApplicationEvent(UserRegisterEvent event) {

        User user = event.getUser();

        // do something

        log.info("ApplicationLister<UserRegisterEvent>注册信息,用户名:" + user.getUsername() + ",密码:" + user.getPassword());

    }
}

该接口是继承了 ApplicationListener、Ordered 的子类,可以监听所有的事件,通过对支持的事件源(supportsSourceType)和支持的事件(supportsEventType)进行校验来实现对指定事件的监听,通过定义 getOrder() 方法来指定该监听者处理事件的执行顺序;具体的处理代码也是在 onApplicationEvent(E event) 中实现。

@Component
@Slf4j
public class UserRegisterListener implements SmartApplicationListener {

    /**
     * Determine whether this listener actually supports the given event type.
     *
     * @param eventType the event type (never {@code null})
     */
    @Override
    public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
        // support UserRegisterEvent.class
        return eventType == UserRegisterEvent.class;
    }

    /**
     * Determine whether this listener actually supports the given source type.
     * <p>The default implementation always returns {@code true}.
     *
     * @param sourceType the source type, or {@code null} if no source
     */
    @Override
    public boolean supportsSourceType(Class<?> sourceType) {
        // support UserServiceImpl which publish event
        return sourceType == UserServiceImpl.class;
    }

    /**
     * Determine this listener's order in a set of listeners for the same event.
     * <p>The default implementation returns {@link #LOWEST_PRECEDENCE}.
     */
    @Override
    public int getOrder() {
        // 0 is highest priority
        return 0;
    }

    @Override
    public String getListenerId() {
        return null;
    }

    /**
     * Handle an application event.
     *
     * @param event the event to respond to
     */
    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        // change event type into target event
        UserRegisterEvent userRegisterEvent = (UserRegisterEvent) event;

        // get user
        User user = userRegisterEvent.getUser();

        // do something

        // print
        log.info("注册监听器001:执行顺序:" + getOrder());
        log.info("注册信息,用户名:" + user.getUsername() + ",密码:" + user.getPassword());
    }
}

Spring 中的事件发布比较简单,可以使用顶层接口 ApplicationEventPublisher 进行发布,也可以使用 Spring 上下文 ApplicationContext 进行发布。

当一个类实现了这个接口(ApplicationContextAware)之后,这个类就可以方便获得ApplicationContext中的所有bean。换句话说,就是这个类可以直接获取spring配置文件中,所有有引用到的bean对象。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值