java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Spring事件发布机制

Spring中事件发布机制及流程详解

作者:爱敲代码的小楚

这篇文章主要介绍了Spring中事件发布机制及流程详解,在分析源码的过程中,也是大量使用了事件机制,在我分析的这篇博客中,有不少地方都运用了事件发布机制,所以本文的目的是从SpringBoot中学习到事件的发布流程,需要的朋友可以参考下

一、角色

在这里插入图片描述

事件类

ApplicationEvent:定义事件类型
|------ApplicationContextEvent:ApplicationContext引发的事件的基类。
        |------ContextClosedEvent:容器关闭事件
        |------ContextRefreshedEvent:容器刷新事件

事件发布者

ApplicationEventPublisher:将应用程序事件通知此应用程序注册的所有侦听器。

事件监听者

ApplicationListener:由应用程序事件侦听器实现的接口。

事件广播器

ApplicationEventMulticaster:
|------AbstractApplicationEventMulticaster:提供了基本的侦听器注册功能
        |------SimpleApplicationEventMulticaster:实现事件通知具体方式

二、角色负责的功能

事件广播器

ApplicationEventMulticaster接口

定义规范:

	// 把事件事件监听者加入集合
 	void addApplicationListener(ApplicationListener<?> listener);
 	// 把事件事件监听者加入集合
    void removeApplicationListener(ApplicationListener<?> listener);
    /**
     *  最终推送时间消息也会经过这个接口方法来处理谁该接收事件
     *
     * @param event
     */
    void multicastEvent(ApplicationEvent event);

AbstractApplicationEventMulticaster抽象类 实现了:

public abstract class AbstractApplicationEventMulticaster implements ApplicationEventMulticaster, BeanFactoryAware {
	// 存放所有ApplicationListener的集合
 public final LinkedHashSet<ApplicationListener<ApplicationEvent>>
            applicationListeners =  new LinkedHashSet();

	/**
     * 方法主要是摘取符合广播事件中的监听处理器,具体过滤动作在 supportsEvent 方法中。
     * @param event
     * @return
     */
 	protected Collection<ApplicationListener> getApplicationListeners(ApplicationEvent event){
        LinkedList<ApplicationListener> allListeners = new LinkedList<>();
        for (ApplicationListener<ApplicationEvent> listener : applicationListeners){
            if(supportsEvent(listener, event)) allListeners.add(listener);
        }
        return allListeners;
    }
    /**
     * 监听器是否对该事件感兴趣
     * 主要包括对 Cglib、Simple 不同实例化需要获取目标
     * Class,Cglib 代理类需要获取父类的 Class,普通实例化的不需要。接下来就是通过
     * 提取接口和对应的 ParameterizedType 和 eventClassName,方便最后确认是否为
     * 子类和父类的关系,以此证明此事件归这个符合的类处理。
     * @param applicationListener
     * @param event
     * @return
     */
    private boolean supportsEvent(ApplicationListener<ApplicationEvent> applicationListener, ApplicationEvent event) {

        Class<? extends ApplicationListener> listenerClass = applicationListener.getClass();
        // 按照 CglibSubclassingInstantiationStrategy、
        // SimpleInstantiationStrategy 不同的实例化类型,需要判断后获取目标 class
        Class<?> targetClass = ClassUtils.isCglibProxyClass(listenerClass) ?
                listenerClass.getSuperclass() : listenerClass;
        Type genericInterface = targetClass.getGenericInterfaces()[0];

        Type actualTypeArgument = ((ParameterizedType) genericInterface).getActualTypeArguments()[0];
        String className = actualTypeArgument.getTypeName();

        Class<?> eventClassName;
        try {
            eventClassName = Class.forName(className);
        } catch (ClassNotFoundException e) {
            throw new BeansException("wrong event class name: " + className);
        }
        // 判定此 eventClassName 对象所表示的类或接口与指定的 event.getClass() 参数所
        // 示的类或接口是否相同,或是否是其超类或超接口。
        // isAssignableFrom 是用来判断子类和父类的关系的,或者接口的实现类和接口的关系的,
        // 默认所有的类的终极父类都是 Object。如果 A.isAssignableFrom(B)结果是 true,证明 B 可以转换成
        // 为 A,也就是 A 可以由 B 转换而来。
        return eventClassName.isAssignableFrom(event.getClass());
    }
	......
}

SimpleApplicationEventMulticaster类 实现了:

public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {
	@Override
    public void multicastEvent(ApplicationEvent event) {
        for(final ApplicationListener listener : getApplicationListeners(event)){
            listener.onApplicationEvent(event);
        }
    }
    .......
}

事件发布者

因为这边事件都是ApplicationContextEvent,Application是对Spring应用上下的管理。所以这边充当事件发布者的是AbstractApplicationContext。 AbstractApplicationContext 间接实现ApplicationEventPublisher

public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {
	private ApplicationEventMulticaster applicationEventMulticaster;
	@Override
    public void refresh() throws BeansException {
    	.....
    	// 一开始就创建了事件广播器
    	// 6. 初始化事件发布者
        initApplicationEventMulticaster();
	    .......
	    // 9. 发布容器刷新完成事件(发布是容器刷新事件)
        finishRefresh();
    }
    // 创建事件广播器
    private void initApplicationEventMulticaster() {
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();
        this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
        beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
    }
    private void finishRefresh() {
        publishEvent(new ContextRefreshedEvent(this));
    }

    @Override
    public void publishEvent(ApplicationEvent event) {
        applicationEventMulticaster.multicastEvent(event);
    }
	.......
}

事件监听者

当我们关心spring容器什么时候刷新,或者想在spring容器刷新的时候做一些事情。 监听关心的事件,主要就是在ApplicationListener中写对应的事件。 spring容器在刷新完容器,就会调用该方法。

public class ContextRefreshedEventListener implements ApplicationListener<ContextRefreshedEvent> {
    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        System.out.println("刷新事件(容器刷新完成):" + this.getClass().getName());
    }
}

三、使用spring中的事件机制

1.写一个事件类(暂定我们关心的是application上下文的事件)

public class CustomEvent extends ApplicationContextEvent {

    private Long id;
    private String message;

    /**
     * Constructs a prototypical Event.
     *
     * @param source The object on which the Event initially occurred.
     * @throws IllegalArgumentException if source is null.
     */
    public CustomEvent(Object source,Long id, String message) {
        super(source);
        this.id = id;
        this.message = message;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}

2.事件发布者

@Test
    public void test_event(){
        ClassPathXmlApplicationContext applicationContext =
                new ClassPathXmlApplicationContext("classpath:spring.xml");

        applicationContext.publishEvent(new CustomEvent(applicationContext, 101912455552221L, "事件发布成功!"));
        //applicationContext.registerShutdownHook();
    }

3.写对应的监听者实现就可以了

public class CustomEventListener implements ApplicationListener<CustomEvent> {
    @Override
    public void onApplicationEvent(CustomEvent event) {
        System.out.println("收到:" + event.getSource() + "消息;时间:" + new Date());
        System.out.println("消息:" + event.getId() + ":" + event.getMessage());
    }
}

四、整体流程

在这里插入图片描述

到此这篇关于Spring中事件发布机制及流程详解的文章就介绍到这了,更多相关Spring事件发布机制内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文