如何使用spring配置Async和Sync Event发布者

时间:2014-10-09 10:23:51

标签: java spring asynchronous

我正在尝试使用spring事件实现事件框架。我开始知道spring事件框架的默认行为是sync。但是在Spring上下文初始化期间,如果它找到一个id为applicationEventMulticaster的bean,它就会表现为Async。

现在我想在我的应用程序中同时拥有同步和异步事件发布者,因为某些事件需要同步发布。我尝试使用SysncTaskExecutor配置同步事件多播器,但我无法找到将其注入我的AsyncEventPublisher的applicationEventPublisher属性的方法。 我的弹簧配置文件如下

<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor" destroy-method="shutdown">
        <property name="corePoolSize" value="5" />
        <property name="maxPoolSize" value="10" />
        <property name="WaitForTasksToCompleteOnShutdown" value="true" />
    </bean>  

    <bean id="syncTaskExecutor" class="org.springframework.core.task.SyncTaskExecutor" />

    <bean id="customEventPublisher" class="x.spring.event.CustomEventPublisher" />
    <bean id="customEventHandler" class="x.spring.event.CustomEventHandler" />  
    <bean id="eventSource" class="x.spring.event.EventSource" /> 
    <bean id="responseHandler" class="x.spring.event.ResponseHandler" /> 
    <bean id="syncEventSource" class="x.spring.event.syncEventSource" /> 


    <bean id="applicationEventMulticaster" class="org.springframework.context.event.SimpleApplicationEventMulticaster">
        <property name="taskExecutor" ref="taskExecutor" />         
    </bean>    

    <bean id="syncApplicationEventMulticaster" class="org.springframework.context.event.SimpleApplicationEventMulticaster">
        <property name="taskExecutor" ref="syncTaskExecutor" />         
    </bean>    

有人可以帮助我吗?

4 个答案:

答案 0 :(得分:2)

我只需要自己解决这个问题。默认情况下,事件是异步发送的,除非您实现标记器接口,在我的情况下,我将其称为SynchronousEvent。您还需要在配置中使用“执行程序”(我省略了我的代码,因为它是非常定制的)。

@EnableAsync
@SpringBootConfiguration
public class BigFishConfig {

    @Autowired AsyncTaskExecutor executor;

    @Bean
    public ApplicationEventMulticaster applicationEventMulticaster() {
        log.debug("creating multicaster");
        return new SimpleApplicationEventMulticaster() {
            @Override
            public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
                ResolvableType type = eventType != null ? eventType : ResolvableType.forInstance(event);
                if (event instanceof PayloadApplicationEvent 
                        && ((PayloadApplicationEvent<?>) event).getPayload() instanceof SynchronousEvent) 
                    getApplicationListeners(event, type).forEach(l -> invokeListener(l, event));
                else 
                    getApplicationListeners(event, type).forEach(l -> executor.execute(() -> invokeListener(l, event)));
            }
        };
    }
...

答案 1 :(得分:0)

不,你不能这样做,spring initApplicationEventMulticaster只是init一个,而BeanName必须是applicationEventMulticaster。所以你可以选择以下Executor之一:

- org.springframework.core.task.SyncTaskExecutor

- org.springframework.core.task.SimpleAsyncTaskExecutor

- 您自己的执行者:org.springframework.scheduling.concurrent.ThreadPoolTask​​Executor

任何方式,您都可以修改org.springframework.context.event.SimpleApplicationEventMulticaster 要添加逻辑,您可以控制是否需要同步/异步

    /**
 * Initialize the ApplicationEventMulticaster.
 * Uses SimpleApplicationEventMulticaster if none defined in the context.
 * @see org.springframework.context.event.SimpleApplicationEventMulticaster
 */
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 + "]");
        }
    }
}

答案 2 :(得分:0)

我不适合使用stackoverflow进行编辑。请原谅我。

  1. SyncTaskExecutor
  2. 我不需要添加您可以很清楚的评论。这是同步的。此Executor按顺序运行任务,并阻止执行每项任务。

     public class SyncTaskExecutor implements TaskExecutor, Serializable {
    
    /**
     * Executes the given {@code task} synchronously, through direct
     * invocation of it's {@link Runnable#run() run()} method.
     * @throws IllegalArgumentException if the given {@code task} is {@code null}
     */
    @Override
    public void execute(Runnable task) {
        Assert.notNull(task, "Runnable must not be null");
        task.run();
    }
    

    }

    1. SimpleAsyncTaskExecutor
    2. 这个类非常大,所以我只选择代码段。如果你给threadFactory,将从这个工厂检索Thread,或者将创建新的Thread。

          protected void doExecute(Runnable task) {
          Thread thread = (this.threadFactory != null ? this.threadFactory.newThread(task) : createThread(task));
          thread.start();
      }
      
      1. ThreadPoolTask​​Executor类
      2. 这个类使用jdk5当前的pkg ThreadPoolTask​​Executor。但是spring封装了功能。春天擅长这种方式,jdk6的当前和jdk7的当前pkg有一些差别。 这将从ThreadPool获取Thread并重用它,执行每个任务Asynchronized。如果您想了解更多详细信息,请参阅JKD源代码。

答案 3 :(得分:0)

我尝试了以下教程:

https://www.keyup.eu/en/blog/101-synchronous-and-asynchronous-spring-events-in-one-application

它有助于制作同步和异步多播器,并在它们之上创建包装器。确保包装器类(DistributiveEventMulticaster)的名称为 applicationEventMulticaster