一、问题描述

今天使用netty结合spring boot开发了一个网络代理服务器,在开发当中由于需要测试,所以在包名底下新建了一个Launcher的main函数入口,同时保留spring boot的Application入口。

Launcher的入口代码如下:

public class Launcher {
    /**
    static {
        try {
            File file = ResourceUtils.getFile("classpath:logback.xml");
            System.out.println("path:"+file.getAbsolutePath());

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        System.setProperty("logback.configurationFile", "classpath:logback.xml");
    }*/

    public void init(){

        //加载日志配置
        Logger logger = LoggerFactory.getLogger(Launcher.class);

        logger.debug("222");

        CreateProxyRequest request3 = new CreateProxyRequest();
        request3.setProxyEnum(ProxyEnum.websocket);
        ProxyDefinition proxyDefinition3 = service.createServer(request3);
        proxyDefinition3.setLocalPort(8081);
        service.startServer(proxyDefinition3.getId());
    }

    public static void main(String[] agrs){

        new Launcher().init();
    }
}

而spring boot的入口如下:

@SpringBootApplication
public class TcpProxyApplication {

    //public static void main(String[] args) {
    //
    //    SpringApplication.run(TcpProxyApplication.class, args);
    //}
}

这两个运行入口在idea手动运行的时候没有任何问题,但是使用maven命令 mvn package -Dmaven.test.skip=true打包后却提示如下错误:

[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 3.388 s
[INFO] Finished at: 2019-09-15T17:57:40+08:00
[INFO] Final Memory: 27M/117M
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.springframework.boot:spring-boot-maven-plugin:1.3.5.RELEASE:repackage (default) on project park-proxy: Execution default of goal org.springframework.boot:spring-boot-maven-plugin:1.3.5.RELEASE:repackage failed: Unable to find a single main class from the following candidates [io.igx.proxy.Launcher, io.igx.proxy.Test] -> [Help 1]
[ERROR] 
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR] 
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/PluginExecutionException

二、解决办法

信息很多,我们来重点关注下错误提示语句:repackage failed: Unable to find a single main class from the following candidates

中文翻译:

打包失败:从以下候选者中找不到一个单独的入口。这里指的是:io.igx.proxy.Launcherio.igx.proxy.Test

第一次遇到这个问题,心里有点慌,不过冷静想一下就得出了解决办法。既然提示多个候选者,那么我们删掉所有带有main函数的类,只保留一个线上自己需要的即可,删除后再运行打包命令直接打包成功!

所以解决办法是:

删除main函数的类或者隐藏掉main函数(类保留,只删除main函数),只保留一个main函数入口。

三、原因分析

一般利用maven或者别的工具将工程打包为jar包且这个包存在一个main入口(即可执行包)的时候出现这一类问题。根据定义java执行jar的命令:java -jar xxx.jar我们得知,这里默认会从jar的main函数开始执行。这个信息会记录在jar包中的MANIFEST.MF描述文件中:

Main-Class: jar包执行入口(其实就是main函数所在的路径)

四、扩展

Manifest.MF文件被android的同学所熟知,但Jar中也有自己的Manifest结构,用来包含打包工具,程序入口,applet, extionsion`等信息。

其结构如下:

  • Manifest-Version, Signature-Version: manifest/签名 文件的版本
  • Created-By: 生成jar包的java版本
  • Class-Path: 该jar包依赖的外部的class 的相对路径(相对该jar包的路径)
  • Main-Class: jar包执行入口
  • Implementation-, Specification- : 该jar包的描述,版本等信息

和我们熟悉的常规jar不一样,可执行的jar可以将工程中的资源文件打包进去,形成一个完整的包括资源的可执行包。

文章目录