zoukankan      html  css  js  c++  java
  • 聚合maven+spring-boot打包可执行jar

    整整搞了一天,终于解决这个问题了。这里是四个module,module之间存在依赖,打包两个可执行jar,看下最终效果吧

              聚合maven+spring-boot的搭建很简单,和普通的聚合maven没有什么区别。聚合maven+spring-boot打包成可执行jar就不是那么容易了,主要是因为spring-boot的坑有点多啊。普通聚合maven打包我就不说了。就说说和spring-boot一起打包的那些比较大的坑吧。

             一、spring-boot-maven-plugin打包出来的jar是不可依赖的

             比如我有一个root工程,type为pom,下面两个spring-boot工程作为它的module,分别为moduleA和moduleB。假如moduleA依赖于moduleB。如果你在moduleB中使用了spring-boot-maven-plugin的默认配置build,或者在root中使用spring-boot-maven-plugin的默认配置build。很遗憾,你在clean package的时候会发现moduleA找不到moduleB中的类。原因就是默认打包出来的jar是不可依赖的。

             解决方案:

            1、调整你的代码,把spring-boot的东西从moduleB中移走。官方文档是这样说的,但是大部分人不会

                  这么干吧。

            2、官方告诉我们,你如果不想移代码,好吧,我这样来给你解决,给你打两个jar包,一个用来直接执

                  行,一个用来依赖。于是,你需要指定一个属性classifier,这个属性为可执行jar包的名字后缀。比

                  如我设置<classifier>exec</classifier>,原项目名为Vehicle-business。

                  那么我会得到两个jar:Vehicle-business.jar和Vehicle-bussiness-exec.jar

             官方文档位置:84.5 Use a Spring Boot application as a dependency

             总结:回到聚合maven上,如果你在root工程中使用了spring-boot-maven-plugin作为builder,那么你的依赖module一定要用解决方案二来设置。否则你不在root工程中用spring-boot-maven-plugin作为builder,而在需要打包的module上使用。

             二、jdk8一定要指明

             不指明的话在开发工具里运行没有一点问题,如果你没有用到java8的特性打包也没有问题。一旦你用到了java8的特性,而且使用spring-boot-maven-plugin作为builder,一定要指明jdk版本。不然你会收到类似不识别Lambda,请使用resource8这样的错误。

     <properties>
        <java.version>1.8</java.version>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
      </properties>

         三、BOOT-INF陷阱
              这个问题就很恶心了。这个时候你已经打包成功,你会发现运行jar的时候报错为file not found,而且不告诉你是什么文件。你打开jar去看,发现需要的lib,配置文件,class一样也不缺。

              其实这里要说一个概念,spring-boot在打包后,会把文件拷贝到BOOT-INF/Classes之下,这个时候你原来定义的扫描包路径将失效。而这个问题官方文档根本没讲,还是我没有看到。

              这个陷阱在你使用packages定义扫描路径的时候等着你。或者获取工程下文件的时候。对于获取文件的话,可以在原路径前加上classes,当然你要区分开发环境或生产环境的话,你可以使用profile或者conditional来解决。如果是扫描包路径就恶心了,因为你加上classes之后,不报file not found了。而是不报错,只是警告你找不到hibernate的某些xml。但是你很可能根本没有使用hibernate。

              目前我的解法是使用register方法代替packages方法,但是问题就是,如果你的类很多,那将是一件痛苦的事情。还好我这里只需要配置两个基于jersey的公共类。

              顺便吐槽一下官方文档在配置jersey的时候根本没有提到packages方法,自然也就把这个BOOT-INF陷阱给忽略了。官方关于jersey的配置章节为27.2 JAX-RS and Jersey

    最后、举个例子。

              假设工程结构如下

              parent

                     moduleA

                     moduleB

                     moduleC

              其中moduleB被moduleA依赖,A使用jersey,moduleA和moduleC需要打包为可执行jar

              那么我们有两种方式聚合

             方式一 在parent中指定spring-boot-maven-plugin

             parent的pom.xml中的builder

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                 <configuration>
                      <source>1.8</source>
                      <target>1.8</target>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
      </build>

               moduleB的pom.xml中的builder

     <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <classifier>exec</classifier>
                </configuration>
            </plugin>
        </plugins>
    </build>

      其余工程不需要builder

     方法二

                 parent的pom.xml不提供builder

                 moduleA和moduleC的pom.xml中的builder

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                 <configuration>
                      <source>1.8</source>
                      <target>1.8</target>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
      </build>

        最后,两种方法都需要把jersey配置文件中的packages方法换成register方法

    public class JerseyConfig extends ResourceConfig{
        public JerseyConfig() {
           register(RequestContextFilter.class);
           //配置restful package.
           //packages("com.zs.vehicle.rpc");
           //packages("classes/com/zs/vehicle/rpc");
           register(Base.class);
           register(Route.class);
        }
    }
  • 相关阅读:
    【Azure 应用服务】由 Azure Functions runtime is unreachable 的错误消息推导出 ASYNC(异步)和 SYNC(同步)混用而引起ThreadPool耗尽问题
    【Azure API 管理】是否可以将Swagger 的API定义导入导Azure API Management中
    【Azure 应用服务】Azure Function 不能被触发
    【Azure 环境】Azure Key Vault (密钥保管库)中所保管的Keys, Secrets,Certificates是否可以实现数据粒度的权限控制呢?
    【Azure 事件中心】为应用程序网关(Application Gateway with WAF) 配置诊断日志,发送到事件中心
    【Azure 事件中心】azure-spring-cloud-stream-binder-eventhubs客户端组件问题, 实践消息非顺序可达
    【Azure API 管理】Azure API Management通过请求中的Path来限定其被访问的频率(如1秒一次)
    【Azure 环境】前端Web通过Azure AD获取Token时发生跨域问题(CORS Error)
    【Azure 应用服务】记一次Azure Spring Cloud 的部署错误 (az spring-cloud app deploy -g dev -s testdemo -n demo -p ./hellospring-0.0.1-SNAPSHOT.jar --->>> Failed to wait for deployment instances to be ready)
    【Azure 应用服务】App Service中抓取 Web Job 的 DUMP 办法
  • 原文地址:https://www.cnblogs.com/zhujiabin/p/9842403.html
Copyright © 2011-2022 走看看