真棒:使用Java 11實現應用的模組化

banq發表於2018-08-06
Java 11帶來成熟的模組化系統,OSGI丟一邊去吧,為什麼要遷移到模組系統?

1. 模組能帶來可靠的配置 - 新的模組系統是需要在程式元件裡明確宣告依賴的方法,這種替代料以前預設的但是脆弱的、容易出錯的類路徑機制,好像只要把Jar包放入classpath就大功告成了,其實沒有那麼容易,版本衝突等等非常煩人。

2.強封裝 - 允許元件宣告哪些公共型別可供外部其他元件訪問,哪些不可被訪問。

3.為你的應用程式建立最小的JRE映像。

4.減少應用程式記憶體佔用量。

5.最佳化應用程式啟動時間。


以 Spring PetClinic為案例:
git clone git@github.com:spring-projects/spring-petclinic.git

看看具體怎麼實現模組化:

1. 在src / main / java目錄中建立一個名為module-info.java的檔案,其中包含以下內容:

module spring.petclinic {
}
<p class="indent">


現在,嘗試編譯應用程式時,您會看到很多錯誤,而在以前java 8中則不會出現。這意味著應用程式表現為模組化佈局,並且必須混入模組功能進行了編譯和執行。

可以使用Maven依賴項外掛解析目標列出當前在類路徑中的所有模組名稱,並將它們新增到module-info中:

./mvnw compile org.apache.maven.plugins:maven-dependency-plugin:3.1.1:resolve
<p class="indent">


填入module-info以後變成下面:

open module spring.petclinic {
    requires cache.api;

    requires java.activation;
    requires java.instrument;
    requires java.persistence;
    requires java.sql;
    requires java.transaction;
    requires java.validation;
    requires java.xml.bind;

    requires org.hibernate.validator;

    requires spring.beans;
    requires spring.boot;
    requires spring.boot.autoconfigure;
    requires spring.context;
    requires spring.core;
    requires spring.data.commons;
    requires spring.data.jpa;
    requires spring.tx;
    requires spring.web;
    requires spring.webmvc;

    requires jdk.unsupported;
}
<p class="indent">


open關鍵詞是用於Spring和Hibernate的反射機制.

2.使用maven-jar-plugin建立應用程式jar(僅限於類)並將其複製到modules目錄:

<plugin>
    <artifactId>maven-jar-plugin</artifactId>
    <version>3.1.0</version>
    <configuration>
        <outputDirectory>
            ${project.build.directory}/modules
        </outputDirectory>
    </configuration>
</plugin>
<p class="indent">


3.使用maven-dependency-plugin複製執行時的依賴到modules目錄:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-dependency-plugin</artifactId>
    <version>3.1.1</version>
    <executions>
        <execution>
            <phase>package</phase>
            <goals>
                <goal>copy-dependencies</goal>
            </goals>
            <configuration>
                <outputDirectory>
                    ${project.build.directory}/modules
                </outputDirectory>
                <includeScope>runtime</includeScope>
                <excludeArtifactIds>
                    spring-boot-devtools
                </excludeArtifactIds>
            </configuration>
        </execution>
    </executions>
</plugin>
<p class="indent">

spring-boot-devtools 應該從模組中排除

4.升級 java.persistence 和 java.transaction版本:
<dependency>
    <groupId>org.hibernate.javax.persistence</groupId>
    <artifactId>hibernate-jpa-2.1-api</artifactId>
    <version>1.0.2.Final</version>
</dependency>
<dependency>
    <groupId>org.jboss.spec.javax.transaction</groupId>
    <artifactId>jboss-transaction-api_1.2_spec</artifactId>
    <version>1.1.1.Final</version>
</dependency>

 


在spring-boot-starter-data-jpa中排除對舊javax.transaction的依賴項:

<exclusions>
    <exclusion>
        <artifactId>javax.transaction-api</artifactId>
        <groupId>javax.transaction</groupId>
    </exclusion>
<p class="indent">


5.修改maven-surefire-plugin配置以禁用分叉程式:

<configuration>
    <forkCount>0</forkCount>
</configuration>
<p class="indent">

當存在module-info.java並且啟用了fork程式時,surefire會建立一個包含模組和未命名模組的混合類路徑,從而導致模組可見性問題並阻止應用程式啟動。

6.打包並測試應用程式。

./mvnw clean package

7.使用Java模組系統執行應用程式:

java --add-opens java.base/java.lang=spring.core,javassist \
--module-path target/modules \
--module spring.petclinic/org.springframework.samples.petclinic.PetClinicApplication

<p class="indent">

由於Spring和Hibernate依賴項需要JDK反射訪問,因此需要--add -opens。

8.如果使用以下命令設定模組main-class屬性,則可以刪除使用module引數指定的主類:

jar --update \
    --file=target/modules/spring-petclinic-2.0.0.BUILD-SNAPSHOT.jar \
    --main-class=org.springframework.samples.petclinic.PetClinicApplication
<p class="indent">


9.為了自動執行上一步,您可以新增exec-maven-plugin:

<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>exec-maven-plugin</artifactId>
    <version>1.6.0</version>
    <executions>
        <execution>
            <id>module-main-class</id>
            <phase>package</phase>
            <goals>
                <goal>exec</goal>
            </goals>
            <configuration>
                <executable>jar</executable>
                <arguments>
                    <argument>
                        --update
                    </argument>
                    <argument>
                        --file=${project.build.directory}/modules/${project.build.finalName}.jar
                    </argument>
                    <argument>
                        --main-class=org.springframework.samples.petclinic.PetClinicApplication
                    </argument>
                    <argument>
                        --module-version=${project.version}
                    </argument>
                </arguments>
            </configuration>
        </execution>
    </executions>
</plugin>
<p class="indent">


10.現在您可以不需要自己宣告主類的情況下執行應用程式:

./mvnw clean package
java --add-opens java.base/java.lang=spring.core,javassist \
--module-path=target/modules \
--module spring.petclinic
<p class="indent">


It’s time! Migrating to Java 11 – criciumadev – Me

相關文章