Jmix version: 2.3.4
Jmix Studio plugin version: 2.3.3-241
IntelliJ version: GIGA IDE 2024.1.1 (Community Edition)
Здраствуйте!
Добрался до этапа развертывания, для начала решил попробовать с jar-файлом. Сразу же решил вынести настройки во внешний файл, а именно сделать файл my.properties, в котором указать настройки бд, путь доступа к шаблонам email, настройки других баз для синхронизации и т.п.
Судя по документации Spring boot, если положить файл с расширением .properties (я пробовал и просто application.properties, без переименования), то он сам просканирует папки и применит этот файл. Однако, данный способ не сработал.
Сделал кастомный класс:
@Configuration
@PropertySource(value = "file:${home}/my.properties", ignoreResourceNotFound = true)
public class AppConfig {
}
И добавил в главный класс:
@Bean
@Primary
AppConfig appConfig() {
return new AppConfig();
}
Не знаю нужно ли было делать второе, но на всякий случай, и вроде ничего не сломалось.
Окей, скопировал из resources
файл application.properties
и переименовал его в my.properties
. Для начала поменял в нём простую настройку server.port=8095
на 8097
и попробовал запустить через консоль java -jar -Dhome=D:/proga D:/proga/myApp-1.0.jar
.
Судя по логам файл он нашёл, но проигнорировал его настройки и запустился, используя внутренний application.properties
. Я удалил из внутреннего файла application.properties
строку server.port
, порт сменился по дефолту на 8080
, пересобрал jar-файл (дальше не буду говорить что после каждого изменения пересобирал проект) и запустился через консоль той-же командой, увидел в консоли что он принял порт из внешнего файла и стал 8097
.
Таким образом я сделал вывод, что внутренний файл application.properties
имеет приоритет над внешним, и в случае одинаковых настроек, берёт из внутреннего, проверил это ещё на нескольких настройках. Хотя в документации Spring написано ровно обратное.
Попробовал полностью стереть содержимое application.properties, собрать jar и запуститься только на внешних настройках, вылетает ошибка:
2024-10-08T15:52:34.658+03:00 INFO 19924 --- [ main] org.quartz.core.QuartzScheduler : JobFactory set to: org.springframework.scheduling.quartz.SpringBeanJobFactory@60431728
2024-10-08T15:52:34.690+03:00 INFO 19924 --- [ main] org.quartz.core.QuartzScheduler : Scheduler quartzScheduler_$_NON_CLUSTERED shutting down.
2024-10-08T15:52:34.690+03:00 INFO 19924 --- [ main] org.quartz.core.QuartzScheduler : Scheduler quartzScheduler_$_NON_CLUSTERED paused.
2024-10-08T15:52:35.150+03:00 INFO 19924 --- [ main] org.quartz.core.QuartzScheduler : Scheduler quartzScheduler_$_NON_CLUSTERED shutdown complete.
2024-10-08T15:52:35.150+03:00 WARN 19924 --- [ main] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'quartz_QuartzService': Unsatisfied dependency expressed through field 'scheduler': Error creating bean with name 'quartzScheduler' defined in class path resource [org/springframework/boot/autoconfigure/quartz/QuartzAutoConfiguration.class]: Couldn't retrieve trigger: Bad value for type long : \x
2024-10-08T15:52:35.150+03:00 INFO 19924 --- [ main] i.j.d.impl.JmixEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'main'
2024-10-08T15:52:35.165+03:00 INFO 19924 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown initiated...
2024-10-08T15:52:35.165+03:00 INFO 19924 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown completed.
2024-10-08T15:52:35.165+03:00 INFO 19924 --- [ main] o.apache.catalina.core.StandardService : Stopping service [Tomcat]
2024-10-08T15:52:35.181+03:00 INFO 19924 --- [ main] .s.b.a.l.ConditionEvaluationReportLogger :
Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled.
2024-10-08T15:52:35.212+03:00 ERROR 19924 --- [ main] o.s.boot.SpringApplication : Application run failed
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'quartz_QuartzService': Unsatisfied dependency expressed through field 'scheduler': Error creating bean with name 'quartzScheduler' defined in class path resource [org/springframework/boot/autoconfigure/quartz/QuartzAutoConfiguration.class]: Couldn't retrieve trigger: Bad value for type long : \x
Полный стак-трейс:
Спойлер
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'quartz_QuartzService': Unsatisfied dependency expressed through field 'scheduler': Error creating bean with name 'quartzScheduler' defined in class path resource [org/springframework/boot/autoconfigure/quartz/QuartzAutoConfiguration.class]: Couldn't retrieve trigger: Bad value for type long : \x
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.resolveFieldValue(AutowiredAnnotationBeanPostProcessor.java:788) ~[spring-beans-6.1.13.jar!/:6.1.13]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:768) ~[spring-beans-6.1.13.jar!/:6.1.13]
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:145) ~[spring-beans-6.1.13.jar!/:6.1.13]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:509) ~[spring-beans-6.1.13.jar!/:6.1.13]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1439) ~[spring-beans-6.1.13.jar!/:6.1.13]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:599) ~[spring-beans-6.1.13.jar!/:6.1.13]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:522) ~[spring-beans-6.1.13.jar!/:6.1.13]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:337) ~[spring-beans-6.1.13.jar!/:6.1.13]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-6.1.13.jar!/:6.1.13]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:335) ~[spring-beans-6.1.13.jar!/:6.1.13]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) ~[spring-beans-6.1.13.jar!/:6.1.13]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:975) ~[spring-beans-6.1.13.jar!/:6.1.13]
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:971) ~[spring-context-6.1.13.jar!/:6.1.13]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:625) ~[spring-context-6.1.13.jar!/:6.1.13]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) ~[spring-boot-3.2.10.jar!/:3.2.10]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:754) ~[spring-boot-3.2.10.jar!/:3.2.10]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:456) ~[spring-boot-3.2.10.jar!/:3.2.10]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:335) ~[spring-boot-3.2.10.jar!/:3.2.10]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1363) ~[spring-boot-3.2.10.jar!/:3.2.10]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1352) ~[spring-boot-3.2.10.jar!/:3.2.10]
at ru.sfi.SFIApplication.main(SFIApplication.java:33) ~[!/:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:569) ~[na:na]
at org.springframework.boot.loader.launch.Launcher.launch(Launcher.java:91) ~[SFI-1.0.jar:1.0]
at org.springframework.boot.loader.launch.Launcher.launch(Launcher.java:53) ~[SFI-1.0.jar:1.0]
at org.springframework.boot.loader.launch.JarLauncher.main(JarLauncher.java:58) ~[SFI-1.0.jar:1.0]
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'quartzScheduler' defined in class path resource [org/springframework/boot/autoconfigure/quartz/QuartzAutoConfiguration.class]: Couldn't retrieve trigger: Bad value for type long : \x
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1806) ~[spring-beans-6.1.13.jar!/:6.1.13]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:600) ~[spring-beans-6.1.13.jar!/:6.1.13]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:522) ~[spring-beans-6.1.13.jar!/:6.1.13]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:337) ~[spring-beans-6.1.13.jar!/:6.1.13]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-6.1.13.jar!/:6.1.13]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:335) ~[spring-beans-6.1.13.jar!/:6.1.13]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) ~[spring-beans-6.1.13.jar!/:6.1.13]
at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254) ~[spring-beans-6.1.13.jar!/:6.1.13]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1443) ~[spring-beans-6.1.13.jar!/:6.1.13]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1353) ~[spring-beans-6.1.13.jar!/:6.1.13]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.resolveFieldValue(AutowiredAnnotationBeanPostProcessor.java:785) ~[spring-beans-6.1.13.jar!/:6.1.13]
... 27 common frames omitted
Caused by: org.quartz.JobPersistenceException: Couldn't retrieve trigger: Bad value for type long : \x
at org.quartz.impl.jdbcjobstore.JobStoreSupport.retrieveTrigger(JobStoreSupport.java:1538) ~[quartz-2.3.2.jar!/:na]
at org.quartz.impl.jdbcjobstore.JobStoreSupport$12.execute(JobStoreSupport.java:1527) ~[quartz-2.3.2.jar!/:na]
at org.quartz.impl.jdbcjobstore.JobStoreCMT.executeInLock(JobStoreCMT.java:245) ~[quartz-2.3.2.jar!/:na]
at org.quartz.impl.jdbcjobstore.JobStoreSupport.executeWithoutLock(JobStoreSupport.java:3800) ~[quartz-2.3.2.jar!/:na]
at org.quartz.impl.jdbcjobstore.JobStoreSupport.retrieveTrigger(JobStoreSupport.java:1524) ~[quartz-2.3.2.jar!/:na]
at org.quartz.core.QuartzScheduler.getTrigger(QuartzScheduler.java:1505) ~[quartz-2.3.2.jar!/:na]
at org.quartz.impl.StdScheduler.getTrigger(StdScheduler.java:508) ~[quartz-2.3.2.jar!/:na]
at org.springframework.scheduling.quartz.SchedulerAccessor.addTriggerToScheduler(SchedulerAccessor.java:300) ~[spring-context-support-6.1.13.jar!/:6.1.13]
at org.springframework.scheduling.quartz.SchedulerAccessor.registerJobsAndTriggers(SchedulerAccessor.java:244) ~[spring-context-support-6.1.13.jar!/:6.1.13]
at org.springframework.scheduling.quartz.SchedulerFactoryBean.afterPropertiesSet(SchedulerFactoryBean.java:507) ~[spring-context-support-6.1.13.jar!/:6.1.13]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1853) ~[spring-beans-6.1.13.jar!/:6.1.13]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1802) ~[spring-beans-6.1.13.jar!/:6.1.13]
... 37 common frames omitted
Caused by: org.postgresql.util.PSQLException: Bad value for type long : \x
at org.postgresql.jdbc.PgResultSet.toLong(PgResultSet.java:3328) ~[postgresql-42.6.2.jar!/:42.6.2]
at org.postgresql.jdbc.PgResultSet.getLong(PgResultSet.java:2540) ~[postgresql-42.6.2.jar!/:42.6.2]
at org.postgresql.jdbc.PgResultSet.getBlob(PgResultSet.java:456) ~[postgresql-42.6.2.jar!/:42.6.2]
at org.postgresql.jdbc.PgResultSet.getBlob(PgResultSet.java:442) ~[postgresql-42.6.2.jar!/:42.6.2]
at com.zaxxer.hikari.pool.HikariProxyResultSet.getBlob(HikariProxyResultSet.java) ~[HikariCP-5.0.1.jar!/:na]
at org.quartz.impl.jdbcjobstore.StdJDBCDelegate.getObjectFromBlob(StdJDBCDelegate.java:3190) ~[quartz-2.3.2.jar!/:na]
at org.quartz.impl.jdbcjobstore.StdJDBCDelegate.selectTrigger(StdJDBCDelegate.java:1780) ~[quartz-2.3.2.jar!/:na]
at org.quartz.impl.jdbcjobstore.JobStoreSupport.retrieveTrigger(JobStoreSupport.java:1536) ~[quartz-2.3.2.jar!/:na]
... 48 common frames omitted
Возвращаешь настройки во внутренний файл и запускаешься через IDEA - всё работает с этими же настройками, собираешь jar-файл с заполненными внутренними настройками, jar запускается (без внешних).
Подскажите, что не так и есть ли элегантное решение хранить внешние настройки (email, ldap, BD, пути к шаблонам эл. почты и т.п) в одной папке с jar-файлом?
p.s.: гуглил вопрос в такой формулировке, везде пишут просто положите файл .properties в одну папку с jar-файлом и будет всё супер. Через консоль может вариант, т.к. они точно имеют высший приоритет, но слишком дофига параметров, на целый лист.
UPDATE 1:
Не знаю надо ли отдельную тему с вопросом задавать, пока не понял связаны они или нет.
Разрабатывал с использованием базы Postgres
, всё changelog удалил. Через IDEA всё запускается, data store говорит что база соответствует сущностям. Перед упаковкой в jar-файл меняю адрес базы на новый в том самом application.properties
(т.к. он в любом случае поменяется), соответственно я имею jar-файл с программой и новую чистую БД.
То, есть, судя по моей логике и документации, при первом запуске приложения (jar-файла) должна просмотреться база, понять что там пусто и сгенерить новый changelog
для всех-всех сущностей.
Однако, программа создаёт только таблицы, которые указаны в init-changelog’ах и при дальнейшем запуске сваливается с ошибкой, т.к. пытается обратиться к таблицам, которых не существует (@PostConstruct методы). И при просмотре таблиц в БД видно, что ни одной моей таблицы нет.
Если проделать такой же трюк с новой базой через IDEA, то генерится новый changelog
и всё благополучно запускается.
Вопрос: так задумано и что делать чтобы через jar-файл создавались все таблицы, или не задумано?)