如何告诉Spring Boot在可执行的JAR文件中使用哪个主类?

212
Execution default of goal 
org.springframework.boot:spring-boot-maven-plugin:1.0.1.RELEASE:repackage 
failed: 
Unable to find a single main class from the following candidates

我的项目有多个带有 main 方法的类。我该如何告诉Spring Boot Maven插件应该使用哪个类作为主类?


2
java -cp myjar.jar MyClass - Evgeni Dimitrov
4
@Evgeni: 这是一个运行时标志。它并没有执行到那一步。它在构建过程中失败了。 - Thilo
11个回答

302

在 pom 文件中添加起始类:

<properties>
    <!-- The main class to start by executing java -jar -->
    <start-class>com.mycorp.starter.HelloWorldApplication</start-class>
</properties>
或者
<build>
<plugins>
    <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>             
        <configuration>    
            <mainClass>com.mycorp.starter.HelloWorldApplication</mainClass>
        </configuration>
    </plugin>
</plugins>
</build>

不需要禁用任何东西。或者我有什么遗漏吗? - Dave Syer
32
请注意,如果您使用spring-boot-starter-parent pom,则此答案是正确的。在这种情况下,“start-class”属性将应用于spring-boot-maven-plugin的“mainClass”配置参数(如果您不使用starter,则可以直接执行此操作)。 - Dave Syer
19
谢谢@ludo_rj,我发现这个方法也可行:mvn clean package -Dstart-class=com.foo.Application,如果想要动态指定使用哪个主类。 - zhuguowei
5
还有一件事要补充,@zhuguowei提到的参数对于Spring Boot Maven插件也是有效的: mvn spring-boot:run -Dstart-class=com.foo.Application。仅当您没有在pom的插件中指定mainClass时才有效。 - Gerardo Roza
两个都对我没用。我还以为是“AND”而不是“OR”?我在MANIFEST.MF中正确看到了Start-Class,但Spring启动了一个不同的带注释的@SpringBootApplication主类。我实际上需要那个类来引导一些东西,所以我不太想改变注释。简单地删除它也没有起作用。Spring似乎会启动它找到的第一个main()。我正在使用spring-boot-starter-parent 2.2.0.M3。 - Angel O'Sphere

141

对于那些使用 Gradle (而不是 Maven)的人:

springBoot {
    mainClass = "com.example.Main"
}

3
Spring Boot 2.x 出现错误:Could not set unknown property 'mainClass' for object of type org.springframework.boot.gradle.dsl.SpringBootExtension - Thunderforge
答案在这个页面下面:https://dev59.com/42Ag5IYBdhLWcg3wwtNp#49716696 - Vitalik

72

如果您不使用spring-boot-starter-parent pom,则从Spring文档中可以得知:

<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <version>1.1.3.RELEASE</version>
    <configuration>
        <mainClass>my.package.MyStartClass</mainClass>
        <layout>ZIP</layout>
    </configuration>
    <executions>
        <execution>
            <goals>
                <goal>repackage</goal>
            </goals>
        </execution>
    </executions>
</plugin>

主类配置可以省略。 - zhaozhi
@zhaozhi,你能解释一下为什么/如何吗? - Renaud

27

对于使用Gradle(而不是Maven)的人,参考Spring Boot Gradle Plugin参考指南(截至Gradle 7.6和Spring Boot 3.0.0):

The main class can also be configured explicitly using the task’s mainClass property:

tasks.named("bootJar") {
  mainClass = 'com.example.ExampleApplication'
}

Alternatively, the main class name can be configured project-wide using the mainClass property of the Spring Boot DSL:

springBoot {
  mainClass = 'com.example.ExampleApplication'
}

哎呀。这就是我已经寻找了两天的大海捞针。谢谢你。这个答案(https://dev59.com/aWIKtIcB2Jgan1zn7WIb#67519950)给了我一个提示要搜索...你在这里提供的内容。还有感谢你在答案中提供Gradle和SB版本。其他答案缺乏版本信息让我发疯。 - granadaCoder
对于未来的读者..我能够使用这个答案中的"tasks.named"..在我的spring-boot应用程序的Manifest.MF中显示"Implementation-Version"。虽然gradle正在创建一个Manifest.MF文件,并且其中有一些"spring boot'ish"的值,但我却无法将一些"众所周知"的属性放入其中。我的下一个评论将是我使用的gradle/groovy代码。但基本上,这帮助了我解决了"如何在gradle springboot项目中使"Implementation-Version"工作的问题。 - granadaCoder
/* 在 spring-boot-app 的 Manifest.MF 文件中显示显式值的魔法(下面)。"Implementation-Version" 驱动 Package.getImplementationVersion 功能 */ tasks.named("bootJar") { manifest { attributes( "Implementation-Title": "HardCodedName123", "Implementation-Version": "HardCodedVersion234", 'Build-Date': new Date().format("yyyy-MM-dd"), 'Build-Time': new Date().format("HH:mm:ssZ") ) } } - granadaCoder
注意,我的Gradle/Groovy代码位于多模块Gradle项目的“顶层”Gradle模块中。我不构建单层的巨石式项目。 - granadaCoder

16
如果您在pom中使用spring-boot-starter-parent,则只需将以下内容添加到您的pom即可:
<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

然后执行 mvn package 命令。

参见这个Spring文档页面

非常重要的一点是需要确保目录结构为src/main/java/你的包名称。


我发现只要复制.java类的包要求,就可以在不修改pom.xml的情况下使该解决方案正常工作。 - user393219

7
我在pom.xml中尝试了以下代码,对我有效。
<build>
<plugins>
    <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        <configuration>
            <mainClass>myPackage.HelloWorld</mainClass> 
        </configuration>
    </plugin>
    <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
            <fork>true</fork>
            <executable>D:\jdk1.8\bin\javaw.exe</executable>
        </configuration>
    </plugin>
</plugins>


我尝试在我的多模块Maven项目中使用你提到的spring-boot-maven-plugin配置,该项目由几个Spring Boot项目组成,并包含Spring Boot作为BOM依赖项,结果非常成功。至于maven-compiler-plugin,我没有指定任何内容,因为我不想让我的POM依赖于平台。 Maven自动分叉,所以我认为你可以忽略这个配置。 - Cheloute

6

从Spring Boot 1.5开始,您可以完全忽略pom或build.gradle中容易出错的字符串字面值。重新打包工具(通过maven或gradle插件)将为您挑选一个使用@SpringBootApplication注释的版本。(有关详细信息,请参见此问题:https://github.com/spring-projects/spring-boot/issues/6496


4

我曾经重命名了我的项目,但它仍然在构建路径中找到旧的Application类。我在“build”文件夹中将其删除后,问题得到解决。


1

对于使用Gradle的Kotlin:

springBoot {
  mainClass.set("com.example.MainKt")
}

1
我看到过这个问题出现在Java 1.9和SpringBoot 1.5.x上,当主类(main-class)没有被明确指定时。

在Java 1.8中,即使没有显式的属性,它也能找到主类(main-class),'mvn package'也可以正常工作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接