tech

Spring Boot事件机制分析

2018-01-18  本文已影响30人  0d1b415a365b

Spring事件机制的四个组件:Event, Publisher, Listener, Multicaster. 类图如下:


spring_event.jpg

几个组件顾名思义,不多赘述.
对应的接口:
事件:ApplicationEvent
事件发布器:ApplicationEventPublisher
事件监听器:ApplicationListener
事件广播器:ApplicationEventMulticaster
在Spring Boot Application的启动代码中, 核心方法:refreshContext(), 这里完成了Spring Context个各种组件初始化:

AbstractApplicationContext.java

public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        // Prepare this context for refreshing.
        prepareRefresh();

        // Tell the subclass to refresh the internal bean factory.
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

        // Prepare the bean factory for use in this context.
        prepareBeanFactory(beanFactory);

        try {
            // Allows post-processing of the bean factory in context subclasses.
            postProcessBeanFactory(beanFactory);

            // Invoke factory processors registered as beans in the context.
            invokeBeanFactoryPostProcessors(beanFactory);

            // Register bean processors that intercept bean creation.
            registerBeanPostProcessors(beanFactory);

            // Initialize message source for this context.
            initMessageSource();

            // Initialize event multicaster for this context.
            initApplicationEventMulticaster();

            // Initialize other special beans in specific context subclasses.
            onRefresh();

            // Check for listener beans and register them.
            registerListeners();

            // Instantiate all remaining (non-lazy-init) singletons.
            finishBeanFactoryInitialization(beanFactory);

            // Last step: publish corresponding event.
            finishRefresh();
        }
    }
}

可以看到与时间相关的两行:initApplicationEventMulticaster和registerListeners

AbstractApplicationContext.java

protected void initApplicationEventMulticaster() {
    ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
        this.applicationEventMulticaster =
                beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
        if (logger.isDebugEnabled()) {
            logger.debug("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
        }
    }
    else {
        this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
        beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
        if (logger.isDebugEnabled()) {
            logger.debug("Unable to locate ApplicationEventMulticaster with name '" +
                    APPLICATION_EVENT_MULTICASTER_BEAN_NAME +
                    "': using default [" + this.applicationEventMulticaster + "]");
        }
    }
}

如果有自己注册的ApplicationEventMulticaster会优先使用自定义广播器,否则就使用SimpleApplicationEventMulticaster
看一下SimpleApplicationEventMulticaster的核心方法:
SimpleApplicationEventMulticaster.java

public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) {
    ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
    for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
        Executor executor = getTaskExecutor();
        if (executor != null) {
            executor.execute(new Runnable() {
                @Override
                public void run() {
                    invokeListener(listener, event);
                }
            });
        }
        else {
            invokeListener(listener, event);
        }
    }
}

看到这里, 我们注意到有一个getTaskExecutor, 而TaskExecutor是Spring提供的一个任务执行器(不懂的可以参考https://docs.spring.io/spring/docs/3.0.0.M4/reference/html/ch25s04.html), Spring会尝试使用TaskExecutor来执行这个事件的发布, 我们来看一下SimpleApplicationEventMulticaster的taskExecutor, 有这么一段注释:

Default is equivalent to {@link org.springframework.core.task.SyncTaskExecutor}

所以有些资料里面就会说事件广播是用SyncTaskExecutor同步执行的. 然鹅, 回到上面初始化广播器的代码, 注意这句:

this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);

这是一个新new出来的广播器, 而且从来没有被调用过setTaskExecutor, 所以实际上根本没用使用taskExecutor. 但最终结果是一样的, 是同步广播事件到所有的Listener. 如果想要异步广播怎么办? 这里就会用到上面提到的自定义广播器了, 自定义一个Multicaster使用AsyncTaskExecutor就可以了.

广播器到此就初始化完成了, 下面开始注册Listeners:

AbstractApplicationContext.java

protected void registerListeners() {
    // Register statically specified listeners first.
    for (ApplicationListener<?> listener : getApplicationListeners()) {
        getApplicationEventMulticaster().addApplicationListener(listener);
    }

    // Do not initialize FactoryBeans here: We need to leave all regular beans
    // uninitialized to let post-processors apply to them!
    String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
    for (String listenerBeanName : listenerBeanNames) {
        getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
    }

    // Publish early application events now that we finally have a multicaster...
    Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
    this.earlyApplicationEvents = null;
    if (earlyEventsToProcess != null) {
        for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
            getApplicationEventMulticaster().multicastEvent(earlyEvent);
        }
    }
}

第一步加载静态定义的Listeners, 这些Listeners从哪来的? 回头看一下启动代码:

SpringApplication.java

SpringApplicationRunListeners listeners = getRunListeners(args);

private SpringApplicationRunListeners getRunListeners(String[] args) {
    Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
    return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
            SpringApplicationRunListener.class, types, this, args));
}

SpringApplicationRunListener接口规定了SpringBoot的生命周期,在各个生命周期广播相应的事件,调用实际的ApplicationListener类。从上面代码可以看到, 他是最先加载到ApplicationContext里的. 也最先被注册到广播器中
接下来就是获取所有ApplicationListener实现类了, 让我们可以方便的使用事件机制来做自己的事情. 只需要实现ApplicationListener接口, 就可以获取到所有事件通知, 所以注意做好事件过滤, 只处理自己关心的事件.
最后还有EventPublisher, 其实跟Multicaster差不多, 从最上面的类图也能看出来, Multicaster其实也是一个Publisher, 所以就不再贴代码了.
Spring事件机制的分析到这里就分析完毕了.

上一篇下一篇

猜你喜欢

热点阅读