LINUX.ORG.RU

Создание дочернего ApplicationContext в другом потоке

 ,


2

1

Для изучения Java и сопутствующих технологий я поставил себе задачу: в свободное от работы время переписать рабочий проект с C++/Qt/OSGEarth на Java/NasaWorldWind.

Это позволит мне познакомиться и с Spring, и с Hibernate и Swing/JavaFX и с WorldWind.

Вот мой репозиторий проекта: https://github.com/popov-aa/GeoEditor Прошу не ругать стиль и отсутствие комментариев. Это чисто учебный проект.

Так как версии интерфейсов будет две, Swing и JavaFX, каждый со своим набором бинов, реализующих окна, я решил что в точке входа (класс com.popov.GeoEditor.GeoEditor) будет создаваться основной ApplicationContext, включающий в себя общие бины.

Далее ссылка на этот ApplicationContext в зависимости от аргументов запуска будет передаваться в объект отвечающий за запуск Swing (com.popov.GeoEditor.launcher.SwingLauncher) или JavaFX (com.popov.GeoEditor.launcher.JavaFXLauncher) версий, в которых будет создаваться свой дочерний ApplicationContext.

Когда я запускаю swing-версию никаких проблем нет:

mvn exec:java -Dexec.args="swing"
Создание всех ApplicationContext и бинов происходит в главном потоке приложения, а в конце просто отображается окно.

Когда запускается JavaFX-версия приложения, указатель на родительский ApplicationContext сохраняется как поле класса JavaFXLauncher и после этого запускается javafx.application.Application.

mvn exec:java -Dexec.args="javafx"

Если создавать дочерний ApplicationContext в потоке JavaFX, в методе start, указатель на родительский ApplicationContext уже будет равен null. Бины JavaFX не будут иметь доступа к общим бинам и ничего не запустится. Если создавать дочерний ApplicationContext в основном потоке, в методе, в который передается указатель на общий ApplicationContext, тогда приложение падает из-за попытке создания JavaFX-окон не в JavaFX-потоке, ибо бины не ленивые.

Собственно, вопрос: почему когда запускается JavaFX-поток обнуляется указатель на родительский ApplicationContext (JavaFXLauncher.generalApplicationContext)? Кто его обнуляет?

Я был уверен в том, что объект в Java будет существовать до тех пор, пока на него есть хоть одна ссылка. Ссылку generalApplicationContext я устанавливаю в методе launch(ApplicationContext applicationContext, String[] args) и больше нигде не модифицирую. И вдруг в другом потоке она оказывается равно null.

Есть какие-то правила, касательно того, что связанные друг с другом ApplicationContext должны быть созданы в одном и том же потоке? Я подобной информации не нашел.

И мне казалось, что в Java, в отличие от Qt, нет таких заморочек, ибо отсутствуют встроенные очереди событий.



Последнее исправление: popov-aa (всего исправлений: 2)

Если уж используешь спринг, то посмотри на spring boot, который облегчит некоторые задачи.

Нет надо создавать несколько applicationContext, у спринга есть такая штука как профили. В итоге ты можешь запускать один контекст, но туда добавлять в зависимости от профиля бины swing-а или javafx.

ma1uta ★★★
()

То, что указатель null может говорить о том, что applicationContext передал в один экземпляр, а запускаешь другой. Надо код смотреть.

ma1uta ★★★
()
Ответ на: комментарий от ma1uta

Посмотрел код, так и есть.

https://github.com/popov-aa/GeoEditor/blob/master/src/main/java/com/popov/GeoEditor/launcher/JavaFXLauncher.java
Проинициализровано поле:

private ApplicationContext generalApplicationContext;
После чего вызвал статический метод, который создал новый экземпляр класса:
launch();

Aber ★★★★★
()

Скорее всего launch создает новый объект твоего Application. Ну и ещё твой метод инициализации не совсем потокобезопасный.

maxcom ★★★★★
()
Ответ на: комментарий от maxcom

Точно. Я ведь помнил об этом нюансе, а тут забыл. Объявил generalApplicationContext статическим и все заработало. Спасибо.

popov-aa
() автор топика
Ответ на: комментарий от dzidzitop

Я думаю что он безопасный, потому что launch сам стартует новый поток, а это даёт гарантии. Но явно документация этого не обещает. Я думаю безопаснее использовать какой-нибудь другой способ передачи параметров в приложение.

maxcom ★★★★★
()
Ответ на: комментарий от maxcom

Какой например?

Сейчас получается в основном потоке создается экземпляр JavaFXLauncher, затем вызывается статический метод launch Application, который внутри создает свой экземпляр JavaFXLauncher.

Это лютая кривизна на мой взгляд.

В голову приходит только один способ: в главном потоке запустить дополнительный поток, который будет в цикле проверять состояние статического поля JavaFXLauncher, которое будет установлено после инициализации в графическом потоке.

Не многим лучше. Какие есть более грациозные способы?

popov-aa
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.