当前位置: 首页 > 知识库问答 >
问题:

为什么订阅在Spring Mongo中起作用而block不起作用?

湛光华
2023-03-14

通过选择KotlinGradleM7Web reactive,我创建了一个全新的Spring初始化项目。

我做了一个小项目:

data class Person (val id: String)

@Component class PersonHandler(val template: ReactiveMongoTemplate) 
{
    init
    {
        println("Initializing")

        val jim: Mono<Person> =  template.save(Person("Jim"))
        val john: Mono<Person> = template.save(Person("John"))
        val jack: Mono<Person> = template.save(Person("Jack"))

        launch(jim)
        launch(john)
        launch(jack)

        println("Finished Initializing")
    }

    fun launch(mono: Mono<Person>)
    {
        mono.subscribe({println(it.id)}, {println("Error")}) // This works
        // mono.block()  This just hangs
    } 
}

我试着将三个人保存到数据库中。保存方法只返回需要执行的Mono。如果我尝试通过简单的订阅来执行它,一切都很好:

Initializing
Finished Initializing
2017-12-21 13:14:39.513  INFO 17278 --- [      Thread-13] org.mongodb.driver.connection            : Opened connection [connectionId{localValue:3, serverValue:158}] to localhost:27017
2017-12-21 13:14:39.515  INFO 17278 --- [      Thread-12] org.mongodb.driver.connection            : Opened connection [connectionId{localValue:4, serverValue:159}] to localhost:27017
2017-12-21 13:14:39.520  INFO 17278 --- [      Thread-14] org.mongodb.driver.connection            : Opened connection [connectionId{localValue:5, serverValue:160}] to localhost:27017
Jim
Jack
John

但是,当我使用而不是订阅时,应用程序挂起:

Initializing
2017-12-21 13:16:47.200  INFO 17463 --- [      Thread-14] org.mongodb.driver.connection            : Opened connection [connectionId{localValue:3, serverValue:163}] to localhost:27017

如果我手动查询数据库,我会看到Jim已被保存,但Jack和John未被保存。

这是窃听器,还是我做错了什么?我希望在代码进一步发展之前保证用户在数据库中,所以我真的很想使用

我不确定它是否相关,但我收到了一个编译器警告

在构造函数中访问非最终属性模板

这里有一个最小的工作示例。它包含两个分支。一个是解决这个问题的方法。

https://github.com/martin-drozdik/spring-mongo-bug-example

共有2个答案

邵兴庆
2023-03-14

我遇到过类似的情况,通过调用“reactiveMongoTemplate.save(model).block()”应用程序被挂起。

这个问题是由@PostConstruct在我的一个类中引起的,该类设计用于在应用程序初始化后创建我的系统用户。我想它是在Spring上下文初始化之前被调用的。

@Configuration
public class InitialDataPostLoader  {
    private Logger logger = LogManager.getLogger(this.getClass());


    @PostConstruct
    public void init() {
        logger.info(String.format(MSG_SERVICE_JOB, "System Metadata initialization"));
        createDefaultUsers();
    }

通过将@PostConstruct替换为ContextReresEventlistener,问题得到了解决。

@Configuration 
public class InitialDataPostLoader implements
 ApplicationListener<ContextRefreshedEvent> {
     private Logger logger = LogManager.getLogger(this.getClass());

     @Override
     public void onApplicationEvent(ContextRefreshedEvent arg0) {

         logger.info(String.format(MSG_SERVICE_JOB, "System Metadata initialization"));
         createDefaultUsers();

     }
罗新
2023-03-14

我认为这可能是Spring框架的缺陷/可用性问题。

首先,让我强调一下subscribeblock之间的区别:

  • 订阅方法启动工作并立即返回。因此,当应用程序的其他部分运行时,您无法保证操作已经完成。
  • block是一个阻塞操作:它触发操作并等待其完成。

对于初始化工作,组合操作和调用块一次可能是最佳选择:

val jim: Mono<Person> =  template.save(Person("Jim"))
val john: Mono<Person> = template.save(Person("John"))
val jack: Mono<Person> = template.save(Person("Jack"))
jim.then(john).then(jack).block();

如前所述,使用block挂起应用程序。我怀疑这可能是Spring上下文初始化的问题——如果我没记错的话,这个过程可能会在某些部分假设一个线程,并在那里使用一个反应式管道调度多个线程的工作。

您能否创建一个最小的示例应用程序(仅使用Java /SpringBoot/Spring Data Reactive Mongo)并报告https://jira.spring.io?

 类似资料:
  • 问题内容: 显然有一些根本尚不了解的东西。 我试图使用户成为Angular Ui.Bootstrap中的Modal模块的用户,但是我发现我的点击没有激活该功能- 因此将其简化为一个非常简单的测试用例,如下所示,当ng-click时我看不到任何调用指向一个函数(alert或console.log),但是当ng- click指向一个仅表示表达式的东西时确实起作用 为什么在第一个示例中未调用? http

  • 拿我正在试验的这个非常简单的框架来说(这样我就可以更深入地学习JavaScript的函数原型。) 这工作很棒。控制台的输出是: 对象{ui:对象,操作:"单击设置openSidebar",函数:对象,运行:函数} 但是,当我尝试这样做时: 在openSidebar()中的的上下文是openSidebar(又名bind没有效果)。控制台输出: 对象{openSidebar:function} 但是,

  • 所以我有了这个网格: 在中有一个没有空格的超长字符串。是具有固定尺寸的占位符。这就产生了上述结果: 但将更改为会得到以下结果: 它会溢出其父级和屏幕大小。为什么它的行为不像Minmax? 码本

  • 我用的是Spring MVC(4.2.2.RELEASE)和Tomcat 8。我的要求是向浏览器发送一个通知。请找到下面的代码。 控制器-------------------@Controller公共类MessageController{/@Autowired private SimpMessageTemplate模板;@Autowire private SimpMessageSendingOpe

  • 问题内容: 我正在尝试从JSON网址获取集合。骨干网确实发送了请求并得到了响应,但是在它之后的集合中没有: 这是我的JavaScript: 响应中的JSON 响应中的Content-Type HTTP标头为。 为什么不将其加载到集合中?JSON是否正确? 一些更多的代码: 问题答案: 是异步的。尝试 要么 要么

  • 问题内容: 我有三部分字符串,每个部分用 符号分隔 。例如, 现在,当我使用这样的方法拆分它时: 它包含整个字符串作为单个元素的数组。 但是当我使用这个: 它完美的作品是什么,我想这意味着 现在的数组包含,并分别对指数0,1和2。 我想知道为什么第一次使用时不起作用,因为我在使用 问题答案: 因为字符是在正则表达式中用来标记行尾的保留令牌。因此,您必须使用进行 转义。