Привет,
до сих пор Vertx был просто скрыт от меня при использовании реактивного API Hibernate (1.0.0.CR4). Но мне нужно предоставить API, чтобы вернуть сеанс, который будет оставаться открытым до тех пор, пока клиент, использующий этот API, не решит закрыть его.
Я запускаю тест Junit, и у меня есть следующий API:
public Stage.Session openSession() throws ExecutionException, InterruptedException {
if (session != null && session.isOpen()) {
session.close();
}
Stage.Session newSession = sessionFactory.openSession();
this.session = newSession;
return newSession ;
}
И в моем тесте junit:
Stage.Session session = deviceRepository.openSession();
Когда я запустил код, я получил ошибку:
This needs to be run on the Vert.x event loop
Я пытался реорганизовать код разными способами, но мне не удалось заставить его работать.
Не могли бы вы посоветовать, как это сделать правильно?
Спасибо.
Привет,
Проблема с сеансом заключается в том, что он не является потокобезопасным, его использование в разных потоках может вызвать проблемы, которые трудно отладить. Кроме того, когда создается новый сеанс, он привязан к контексту Vert.x и после этого должен использоваться в том же контексте.
Обычно этим занимается Hibernate Reactive при использовании SessionFactory#withTransaction
и SessionFactory#withSession
.
Ваши тесты не работают, потому что они выполняются в потоке JUnit, а не в потоке Vert.x.
Один из способов решить эту проблему в JUnit 4 - использовать правило, включенное в библиотеку io.vertx:vertx-unit:4.0.3
:
<strong i="13">@Rule</strong>
public RunTestOnContext vertxContextRule = new RunTestOnContext();
Это обеспечит выполнение ваших тестов в контексте Vert.x.
Однако этого недостаточно, вам также необходимо убедиться, что сеанс привязан к тому же контексту Vert.x, который определен правилом.
Обычно это достигается путем создания настраиваемой службы VertxInstance .
Эта служба сообщает Hibernate Reactive, как получить правильный экземпляр Vert.x для использования при создании сеанса.
Если вы создаете SessionFactory программно, вот пример того, как вы можете это сделать:
Configuration configuration = new Configuration();
StandardServiceRegistryBuilder builder = new ReactiveServiceRegistryBuilder()
.addService( VertxInstance.class, (VertxInstance) () -> getMyVertxInstance())
.applySettings( configuration.getProperties() );
StandardServiceRegistry registry = builder.build();
SessionFactory sessionFactory = configuration.buildSessionFactory( registry );
В качестве альтернативы вы можете определить его с помощью механизма ServiceLoader JDK :
org.hibernate.reactive.vertx.VertxInstance
под
/META-INF/services/
VertxInstance
:
org.myproject.MyVertxProvider
Теперь Hibernate Reactive будет вызывать экземпляр MyVertxProvider
когда ему нужен экземпляр Vert.x, и если ваш код работает в том же контексте Vert.x, все должно работать.
Возвращаясь к тестам, один из способов их исправить:
<strong i="41">@Rule</strong>
public RunTestOnContext vertxContextRule = new RunTestOnContext();
...
Configuration configuration = new Configuration();
StandardServiceRegistryBuilder builder = new ReactiveServiceRegistryBuilder()
.addService( VertxInstance.class, (VertxInstance) () -> vertxContextRule.vertx() )
.applySettings( configuration.getProperties() );
SessionFactory sessionFactory = configuration.buildSessionFactory( builder.build() );
Если вы не используете правило, вы можете запустить код в конкретном контексте Vert.x следующим образом:
Context currentContext = Vertx.currentContext();
currentContext.runOnContext( event -> {
// Here you should be able to use the session
});
Вы должны добавить то, что вы только что написали, в виде FAQ на сайт или где-нибудь еще.
Да, я согласен
@DavideD Очень признателен за ваше объяснение. Спасибо.
Я создал проблему для отслеживания этих изменений в документации / на веб-сайте: https://github.com/hibernate/hibernate-reactive/issues/751
Я собираюсь закрыть этот выпуск. Смело задавайте еще вопросы, еще чего-то непонятно.
Спасибо.
@DavideD Можно ли использовать следующий код, который вы упомянули ранее, с JUnit 5?
Context currentContext = Vertx.currentContext();
currentContext.runOnContext( event -> {
// Here you should be able to use the session
});
Да, это код Vert.x, а не JUnit.
Но это не эквивалентное расширение для JUnit 5:
<strong i="8">@Rule</strong>
public RunTestOnContext vertxContextRule = new RunTestOnContext();
Самый полезный комментарий
Да, я согласен