springboot有两个主启动类时,maven打包(可执行包)会报错,需指定启动主类
我本地写了一个rabbitmq fanout模式的demo。consumer启动类和producer启动类都放到了一个springboot程序里。本地调试通过。
突然有个疑问,springboot项目是怎么来发现主启动类的呢?
我们知道,默认使用maven打包时,是个普通的可供依赖的jar包,仅包含来自项目源的资源和已编译的Java类,并不能单独运行。
鉴于上面的疑问,我在pom里加上spring-boot-maven-plugins,让这个项目作为一个springboot程序。
<build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>
这时,执行mvn package或mvn install命令时,发现报错--无法从两个候选的main程序类来选定一个作为主启动类。具体错误信息如下:
Failed to execute goal org.springframework.boot:spring-boot-maven-plugin:2.2.0.RELEASE:repackage (repackage) on project fanoutx: Execution repackage of goal org.springframework.boot:spring-boot-maven-plugin:2.2.0.RELEASE:repackage failed: Unable to find a single main class from the following candidates [com.fanoutconsumer.FanoutConsumerApplication, com.fanoutproducer.FanoutProducerApplication]
这才知道,在这种情况下,需要通过maven-plugin的configuration/mainClass节点来指定主启动类。
<build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <mainClass>com.fanoutconsumer.FanoutConsumerApplication</mainClass> </configuration> </plugin> </plugins> </build>
当然,话说回来,在企业应用中,我们通常也不会在一个springboot程序里写两个或多个启动类(只会写一个),所以也就不用显式指定启动类了。
springboot可执行程序包默认也是.jar。那么,对于同一个springboot项目,打出来的普通可依赖jar与springboot可执行jar有什么区别呢?
我们看两种情况下的jar包里的文件结构及文件目录
1/2)作为普通可依赖jar包的 fanoutx-1.0-SNAPSHOT.jar
fanoutx-1.0-SNAPSHOT.jar application.yml +com(项目已编译类,.class文件) +META-INF MANIFEST.MF +maven +org.example +fanoutx pom.properties pom.xml
其中,META-INF/MANIFEST.MF内容为:
Manifest-Version: 1.0 Implementation-Title: fanoutx Implementation-Version: 1.0-SNAPSHOT Build-Jdk-Spec: 1.8 Created-By: Maven Archiver 3.4.0
2/2)作为springboot可执行jar包 的 fanoutx-1.0-SNAPSHOT.jar 是一个“胖jar”(有时称为“fat jars”)
fanoutx-1.0-SNAPSHOT.jar +BOOT-INF +classes application.yml +com(项目已编译类,.class文件) +lib (项目依赖的lib包) +META-INF MANIFEST.MF +maven +org.example +fanoutx pom.properties pom.xml +org +springframework +boot +loader +archive +data ExecutableArchiveLauncher.class +jar JarLauncher.class LaunchedURLClassLoader$UseFastConnectionExceptionsEnumeration.class LaunchedURLClassLoader.class Launcher.class MainMethodRunner.class PropertiesLauncher$1.class PropertiesLauncher$ArchiveEntryFilter.class PropertiesLauncher$PrefixMatchingArchiveFilter.class PropertiesLauncher.class +util WarLauncher.class
其中,META-INF/MANIFEST.MF内容为:
Manifest-Version: 1.0 Implementation-Title: fanoutx Implementation-Version: 1.0-SNAPSHOT Start-Class: com.fanoutconsumer.FanoutConsumerApplication Spring-Boot-Classes: BOOT-INF/classes/ Spring-Boot-Lib: BOOT-INF/lib/ Build-Jdk-Spec: 1.8 Spring-Boot-Version: 2.2.0.RELEASE Created-By: Maven Archiver 3.4.0 Main-Class: org.springframework.boot.loader.JarLauncher
可见,主要是后者有个 BOOT-INF ,还有 org/springframework/boot/loader/ 。---------->不仅具有来自项目的已编译Java类,还包括代码需要运行的所有 jar 依赖项,而且还具有启动Spring Boot应用程序所需的所有运行时库。
另外还可以看到,两者的 META-INF/MANIFEST.MF 文件里的内容不同,可执行jar里定义了Jarlauncher 及 Start-Class。
BTW,两者里,pom.xml内容与原始的pom.xml相同。pom.properties定义了artifact
version=1.0-SNAPSHOT groupId=org.example artifactId=fanoutx
【the end】
ref1:Maven-build之spring-boot-maven-plugin
ref2:baidu:Jarlauncher的实现原理
ref3:baidu:Springboot 创建可执行 Jar
当看到一些不好的代码时,会发现我还算优秀;当看到优秀的代码时,也才意识到持续学习的重要!--buguge
本文来自博客园,转载请注明原文链接:https://www.cnblogs.com/buguge/p/16373686.html