java - Spring Data MongoDB 生命周期事件 : is it possible to always handle them synchronously?

标签 java spring spring-data spring-data-mongodb

我正在尝试使用 Spring Data MongoDB 生命周期事件根据 MongoDB 在插入时生成的 ID 来计算“保存后”的字段。 Reference documentation关于另一个事件“保存前”的说明如下:

To intercept an object before it goes into the database, you can register a subclass of org.springframework.data.mongodb.core.mapping.event.AbstractMongoEventListener that overrides the onBeforeSave method. When the event is dispatched, your listener is called and passed the domain object and the converted com.mongodb.Document. The following example shows how to do so:

然后他们提供了一个例子。

我为“保存后”做了类似的事情:

public class MyMongoDbLifecycleListener extends AbstractMongoEventListener<MyModel> {
    @Override
    public void onAfterSave(AfterSaveEvent<MyModel> event) {
        super.onAfterSave(event);

        MyModel model = event.getSource();

        model.computeValueFromTheAssignedId();
    }
}

这在测试中有效,但在预生产测试中我们偶然发现了一个问题:有时(实际上,经常)当对象从 Repository 返回时,值没有被预先计算的 save() 方法。

问题是应用程序事件在我们的应用程序中是异步处理的。我们的配置中有以下内容:

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

SimpleApplicationEventMulticaster 中,有以下代码实际执行多播:

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

所以我们的应用程序上下文异步地多播所有事件并在不同于我们调用save()的线程中调用监听器,所以我们没有保证保存后能看到监听器的效果。

我很困惑。文档措辞(“在......之前拦截对象”)清楚地表明这发生在严格之前转换/保存/任何。但是一个简单的(和自然的)配置更改会破坏这些保证。我怀疑我做错了什么,但我应该如何正确地做呢?

我现在唯一的想法是编写一个多播器的扩展,专门同步处理所有与 MongoDB 相关的事件。这应该行得通,但打破系统行为应该那么容易吗?

最佳答案

这是 SimpleApplicationEventMulticaster 扩展,它允许实现“spring-data-mongodb 事件的同步处理”策略:

public class SystemEventsAreSyncronousMulticaster extends SimpleApplicationEventMulticaster {
    @Override
    public void multicastEvent(ApplicationEvent event, ResolvableType eventType) {
        ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
        for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
            Executor executor = getTaskExecutor();
            if (executor == null || eventMustBeProcessedSynchronously(event)) {
                invokeListener(listener, event);
            } else {
                executor.execute(() -> invokeListener(listener, event));
            }
        }
    }

    private boolean eventMustBeProcessedSynchronously(ApplicationEvent event) {
        return event instanceof MongoMappingEvent;
    }

    private ResolvableType resolveDefaultEventType(ApplicationEvent event) {
        return ResolvableType.forInstance(event);
    }
}

关于java - Spring Data MongoDB 生命周期事件 : is it possible to always handle them synchronously?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56391260/

相关文章:

java - 高阶乘泊松计算

java - 图像包位置

mongodb - Spring data-Mongo DB Query 嵌入数组

java - 单元测试中通过字段 'userService' 表达的不满足的依赖关系

java - Spring WebClient 从 Json 请求中过滤 Null

java - 无法在 Controller 类中使用组件/服务/存储库

java - 为什么我的 jar 不反射(reflect)变化?

java - 通过 GAE Java 重新使用 GAE Python 代码

java - 如何允许未经身份验证的 GET 请求但保护其他 HTTP 方法?

java - 多次使用InputStream