Spring Boot ApplicationListener异步执行

Spring Boot版本


    org.springframework.boot
    spring-boot
    1.3.6.RELEASE

查阅代码会发现,事件的执行在类:SimpleApplicationEventMulticaster

代码块:

private Executor taskExecutor;

protected Executor getTaskExecutor() {
    return this.taskExecutor;
}

@Override
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);
        }
    }
}

设置方法:

@Bean
public SmartInitializingSingleton applicationEventMulticasterInitializer(List eventMulticasters) {
    return () -> {
        for (SimpleApplicationEventMulticaster eventMulticaster : eventMulticasters) {
            //设置任务执行器 这样就实现了异步调用 (缺点是全局的,要么全异步,要么全同步,包括spring框架自身Listener)
            eventMulticaster.setTaskExecutor(Executors.newFixedThreadPool(10));
        }
    };
}

通过使用SmartInitializingSingleton,对现有的SimpleApplicationEventMulticaster进行增强。

SmartInitializingSingleton:

实现该接口后,当所有单例 bean 都初始化完成以后, 容器会回调该接口的方法 afterSingletonsInstantiated。主要应用场合就是在所有单例 bean 创建完成之后,可以在该回调中做一些事情。


以下这个方法会存在问题,导致自定义的Spring Boot事件监听不到,例如:ApplicationStartedEvent、ApplicationReadyEvent

我们看到AbstractApplicationContext类中如下代码,Spring会先获取已经存在的applicationEventMulticaster bean,没有的情况下才会重新创建一个。

APPLICATION_EVENT_MULTICASTER_BEAN_NAME="applicationEventMulticaster"

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 bean,让系统使用我们的ApplicationEventMulticaster

@Bean
public ApplicationEventMulticaster applicationEventMulticaster(BeanFactory beanFactory) {
    SimpleApplicationEventMulticaster eventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
    eventMulticaster.setTaskExecutor(Executors.newFixedThreadPool(10));
    return eventMulticaster;
}

但是这种方式无法覆盖Spring Boot中的ApplicationEventMulticaster变量,由于Spring Boot中的此变量是new出来的

类:EventPublishingRunListener

private final ApplicationEventMulticaster multicaster;

public EventPublishingRunListener(SpringApplication application, String[] args) {
    ...
    // new一个出来
    this.multicaster = new SimpleApplicationEventMulticaster();
    ...
}

private void registerApplicationEventMulticaster(ConfigurableApplicationContext context) {
    // 注册到BeanFactory
    context.getBeanFactory().registerSingleton(
            AbstractApplicationContext.APPLICATION_EVENT_MULTICASTER_BEAN_NAME,
            this.multicaster);
    ...
}

private void publishEvent(SpringApplicationEvent event) {
    // 主要是这一行,Spring Boot直接使用内部变量发送事件
    this.multicaster.multicastEvent(event);
}

public void started() {
    // puublish ApplicationStartedEvent 事件
    publishEvent(new ApplicationStartedEvent(this.application, this.args));
}

其他方法:

使用:@EnableAsync与@Async注解

你可能感兴趣的:(Spring,Boot)