spring事件驱动模型--观察者模式

观察者模式的本质是"对象之间定义一个一对多的依赖,这样,当一个对象的状态发生改变,其所有监听者得到通知

Spring通过ApplicationEvent类和ApplicationListener的接口提供ApplicationContext的事件处理。如果一个bean实现了ApplicationListener的接口并被部署到,如果容器内发生了ApplicationEvent,这个监听bean将收到它

Spring自带了内置事件ContextStartedEvent,ContextRefreshedEvent, ContextStoppedEvent等,你也可以创建自己的自定义事件。 

 

 

使用观察者模式,有三个类是必须的:

事件:ApplicationEvent
事件监听器:ApplicationListener,对监听到的事件进行处理。即 观察者接口
事件广播器:ApplicationEventMulticaster,广播publish事件给所有的监听器。
Spring在ApplicationContext接口的抽象实现类AbstractApplicationContext中完成了事件体系的搭建。
AbstractApplicationContext拥有一个applicationEventMulticaster成员变 量,applicationEventMulticaster提供了容器监听器的注册表。
 
 
 
 
AbstractApplicationContext在refresh()这个容器启动方法中执行初始化操作
 

 1:事件广播器的初始化

用户可以在配置文件中自定义的事件广播器,编号必须为 applicationEventMulticaster,只要实现ApplicationEventMulticaster就可以了,Spring会将其注册成容器的事件广播器,

如果没有找到配置的外部事件广播器,Spring自动使用 SimpleApplicationEventMulticaster作为事件广播器。

 

2: 注册事件监听器:

定义实现 ApplicationListener 接口的bean,  通过调用registerListeners()方法, 使用 ListableBeanFactory 的getBeanNamesForType方法,从BeanDefinitionRegistry中找出所有实现 ApplicationListener 的Bean,将它们注册为容器的事件监听器,实际的操作就是将其添加到事件广播器所提供的监听器注册表中。

 

3: 发布事件

 在AbstractApplicationContext的 publishEvent 方法中, Spring委托ApplicationEventMulticaster将事件通知给所有的事件监听器

 

 

遍历注册的每个监听器,调用每个监听器的onApplicationEvent方法来执行发布操作;如果配置了 Executor, 则会通过Executor线程池来执行发布操作。
 

 

  

以下是一个简单的Demo

 1:定义一个ApplicationEvent 

public class MessageEvent extends ApplicationEvent {

    private static final long serialVersionUID = -1184214144591672917L;

    public MessageEvent(Object source) {
        super(source);
        System.out.println("source=" + source);
    }

    @Override
    public String toString() {
        System.out.println("MessageEvent toString()");
        return super.toString();
    }
}

2: 建立事件处理类, 需要实现ApplicationListener接口

public class ResponseHandler implements ApplicationListener<MessageEvent> {

    @Override
    public void onApplicationEvent(MessageEvent event) {
        System.out.println("[ResponseHandler]event=" + event);
    }
}

3:在配置文件中配置ResponseHandler,使用默认的 SimpleApplicationEventMulticaster,

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:context="http://www.springframework.org/schema/context" xmlns:task="http://www.springframework.org/schema/task"
    xsi:schemaLocation="
          http://www.springframework.org/schema/beans
          http://www.springframework.org/schema/beans/spring-beans.xsd
          http://www.springframework.org/schema/tx
          http://www.springframework.org/schema/tx/spring-tx.xsd
          http://www.springframework.org/schema/context
          http://www.springframework.org/schema/context/spring-context.xsd
          http://www.springframework.org/schema/aop
          http://www.springframework.org/schema/aop/spring-aop.xsd
          http://www.springframework.org/schema/task 
          http://www.springframework.org/schema/task/spring-task.xsd
          http://www.springframework.org/schema/tool
          http://www.springframework.org/schema/tool/spring-tool.xsd">

    <bean id="responseHandler" class="com.mountain.springdemo.entity.ResponseHandler" />
    <task:executor id="pool" pool-size="10" />
    <bean id="applicationEventMulticaster" class="org.springframework.context.event.SimpleApplicationEventMulticaster">
        <property name="taskExecutor" ref="pool" />
    </bean>

运行如下结果如下:

    public static void main(String[] args) {
        AbstractApplicationContext appContext = new ClassPathXmlApplicationContext("/applicationContext.xml");

        appContext.publishEvent(new MessageEvent("okkkkk"));
 
        System.out.println("END...");
    }

 配置文件中配置了Executor ,  并且指定了线程池大小,会生成一个默认的Executor(ThreadPoolTaskExecutor ), 从输出结果可以看出,明显是异步执行。  

source=okkkkk
2018-08-04 20:11:15,529 [main] DEBUG [org.springframework.beans.factory.support.DefaultListableBeanFactory] - Returning cached instance of singleton bean 'responseHandler'
END...
MessageEvent...
[ResponseHandler]event=com.mountain.spring.MessageEvent[source=okkkkk]

 

以上代码中我直接使用了ApplicationContext对象, 不过可以通过实现ApplicationContextAware接口来得到ApplicationContext对象

public class MyApplicationContextAware implements ApplicationContextAware {

    private ApplicationContext applicationContext;
    
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
    
    public void publishEvent(MessageEvent event){
        System.out.println("[MyApplicationContextAware->publishEvent]");
        applicationContext.publishEvent(event);
    }
}

通过获取 MyApplicationContextAware来得到ApplicationContext,完成事件发布操作。

 

参考: https://www.cnblogs.com/fingerboy/p/6393644.html

 

posted @ 2018-08-04 20:44  南极山  阅读(809)  评论(0)    收藏  举报