Spring-Boot executable JAR
Читаю Spring Boot Reference Documentation. Дошел до раздела, где предлагается создать исполняемый файл JAR. Не получается. Проект запускается из IDE, а через командную строку java -jar <name> сыпятся ошибки.
Использую IntelliJ IDEA 2022.1 + Gradle.
UPD. В ответ на комментарий добавляю лог ошибки:
00:28:13.394 [main] ERROR org.springframework.boot.SpringApplication - Application run failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'resourceHandlerMapping' defined in class path resource [org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration$EnableWebMvcConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.web.servlet.HandlerMapping]: Factory method 'resourceHandlerMapping' threw exception; nested exception is java.lang.IllegalStateException: No ServletContext set
at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:658)
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:638)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1352)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1195)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:582)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:953)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:918)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:740)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:415)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:303)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1312)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1301)
at MainKt.main(Main.kt:4)
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.web.servlet.HandlerMapping]: Factory method 'resourceHandlerMapping' threw exception; nested exception is java.lang.IllegalStateException: No ServletContext set
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:185)
at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:653)
... 18 common frames omitted
Caused by: java.lang.IllegalStateException: No ServletContext set
at org.springframework.util.Assert.state(Assert.java:76)
at org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport.resourceHandlerMapping(WebMvcConfigurationSupport.java:591)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:78)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:567)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154)
... 19 common frames omitted
Process finished with exit code 1
Но фактически тут проблема с созданием рабочего JAR-файла, и вопрос адресован в первую очередь тем, у кого получилось это сделать для проекта SpringBoot.
UPD2. Файл build.gradle.kts (безуспешно пробовал несколько мануалов, поэтому сюда публикую таким, какой он был - без изменений):
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
kotlin("jvm") version "1.6.20"
application
}
group = "org.example"
version = "1.0-SNAPSHOT"
repositories {
mavenCentral()
}
dependencies {
implementation("org.springframework.boot:spring-boot-starter-web:2.6.7")
testImplementation(kotlin("test"))
}
tasks.test {
useJUnitPlatform()
}
tasks.withType<KotlinCompile> {
kotlinOptions.jvmTarget = "1.8"
}
application {
mainClass.set("MainKt")
}
JAR создаю средствами IntelliJ IDEA, через командную строку не пробовал.
Ответы (2 шт):
В общем вопрос частично решен. Вот, что мне удалось выяснить.
Сначала исходные данные. Я создал на сайте start.spring.io образ, в который добавил в зависимости только Spring Web. Скачал, открыл в IntelliJ IDEA. Запустил проект. Все работает. Теперь пришло время создать артефакт (запускаемый через java -jar файл): File -> Project Structure -> Artifacts -> + -> JAR -> From module with dependencies... -> Choose main class -> ОК. После этого Build -> Build Artifacts -> Build/Rebuild. В директории (по умолчанию {project root}\out\artifacts\{project name}) создался JAR-файл. При запуске через java -jar {этот файл} программа закрывается с ошибкой. Весь парадокс в том, что я не написал ни одной строчки кода. Пустой по сути проект, который отлично работает из IDE, не запускается в виде отдельного файла. Как это победить, я так и не понял, к сожалению.
Однако получить работающий JAR мне удалось. 2 пути, которые, по своей сути, делают одно и то же:
- Ctrl+E (в Windows) -> Gradle. В открывшемся (по умолчанию справа) окне выбрать Tasks -> build -> build.
- В командной строке в корневой директории проекта выполнить
.\gradle build
Оба варианта создадут JAR-файлы в директории (по умолчанию) {project root}\build\libs. Они отлично запускаются при помощи java -jar.
Вопрос вроде бы решен, но почему артефакт нормально не создается через Build Artefact осталось загадкой.
Процедура создания выполнимого jar для spring boot очень нетривиальна (тут можно почить https://docs.spring.io/spring-boot/docs/current/reference/html/executable-jar.html). intellij не умеет делать такой jar сама, нужно пользоваться плагином к gradle или mvn.
Чтоб не нужно было покидать IDE добавьте себе конфигурацию на запуск gradle задачи. Для этого идите в меню Run -> Edit Configurations. Далее слева в дереве выбирайте Gradle и добавляйте новую конфигурацию плюсиком
Далее задайте имя конфигурации, выберите корневой проект gradle и укажите название задачи (это может быть та, которую вы запускали из командной строки - build так и более специализированная - bootJar:
После сохранения запускать можно с панели инструметов:
или из меню Run -> Run....


