1. 程式人生 > >聚合maven+spring-boot打包可執行jar

聚合maven+spring-boot打包可執行jar

.so mave 一個 route source 兩種 惡心 兩種方法 color

整整搞了一天,終於解決這個問題了。這裏是四個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);
    }
}

聚合maven+spring-boot打包可執行jar