如何透過 Maven 傳遞 JVM 參數
1. 概述
在本教程中,我們將透過 Maven 使用 JVM 參數來執行 Java 程式碼。我們將探索如何將這些參數應用於全域構建,然後重點將它們應用於特定的 Maven 插件。
2. 設定全域 JVM 參數
首先,我們將看到兩種將 JVM 參數套用到主 Maven 進程的不同技術。
2.1.使用命令列
要使用 JVM 參數執行 Java Maven 項目,我們將設定MAVEN_OPTS環境變數。該變數包含 JVM 啟動時使用的參數,並允許我們提供其他選項:
$ export MAVEN_OPTS="-Xms256m -Xmx512m"
在此範例中,我們透過MAVEN_OPTS定義最小和最大堆大小。然後,我們可以透過以下方式運行我們的建置:
$ mvn clean install
我們設定的參數適用於建置的主要過程。
2.2.使用jvm.config文件
自動設定全域 JVM 參數的另一種方法是定義jvm.config檔。我們必須將此檔案放置在專案根目錄下的.mvn資料夾中。該文件的內容是要套用的 JVM 參數。例如,為了模仿我們之前使用的命令列,我們的設定檔將如下所示:
-Xms256m -Xmx512m
3. 將 JVM 參數設定為特定插件
Maven 外掛程式可能會衍生新的 JVM 程序來執行其任務。因此,設定全域參數對它們不起作用。每個插件都定義了設定參數的方式,但大多數配置看起來都很相似。特別是,我們將展示三個廣泛使用的插件的範例: spring-boot Maven 插件、 surefire插件和failsafe插件。
3.1.設定範例
我們的想法是建立一個基本的 Spring 項目,但我們希望程式碼只有在設定一些 JVM 參數時才能運行。
讓我們從編寫我們的服務類別開始:
@Service
class MyService {
int getLength() throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
ArrayList<String> arr = new ArrayList<>();
Field sizeField = ArrayList.class.getDeclaredField("size");
sizeField.setAccessible(true);
return (int) sizeField.get(arr);
}
}
Java 9中模組系統的引入為反射存取帶來了更多的限制。因此,這段程式碼在 Java 8 中編譯,但需要加入–add-open JVM 選項來開啟 java java-base模組的java-util套件,以便在 Java 9 及更高版本中進行反射。
現在,我們可以在其上添加一個簡單的控制器類別:
@RestController
class MyController {
private final MyService myService;
public MyController(MyService myService) {
this.myService = myService;
}
@GetMapping("/length")
Integer getLength() throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
return myService.getLength();
}
}
為了完成我們的設置,讓我們添加主應用程式類別:
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
3.2. Spring-Boot Maven 插件
讓我們新增最新版本的 Maven spring-boot外掛的基本配置:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>3.3.0</version>
</plugin>
我們現在可以透過以下命令運行該專案:
$ mvn spring-boot:run
正如我們所看到的,應用程式成功啟動。但是,當我們嘗試在http://localhost:8080/length上發出GET請求時,我們會收到與下列日誌相關的錯誤:
java.lang.reflect.InaccessibleObjectException: Unable to make field private int java.util.ArrayList.size accessible: module java.base does not "opens java.util" to unnamed module
正如我們在設定過程中所說,我們必須添加一些與反射相關的 JVM 參數以避免此錯誤。特別是,對於spring-boot Maven 插件,我們需要使用jvmArguments配置標籤:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>3.3.0</version>
<configuration>
<jvmArguments>--add-opens java.base/java.util=ALL-UNNAMED</jvmArguments>
</configuration>
</plugin>
我們現在可以重新執行該專案: http://localhost:8080/length上的GET請求現在返回0 ,這是預期的答案。
3.3.萬火插件
首先,讓我們為我們的服務添加一個單元測試:
class MyServiceUnitTest {
MyService myService = new MyService();
@Test
void whenGetLength_thenZeroIsReturned() throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
assertEquals(0, myService.getLength());
}
}
Surefire 外掛程式通常用於透過 Maven 運行單元測試。讓我們天真地加入最新版本外掛的基本配置:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.3.0</version>
<configuration>
<includes>
<include>**/*UnitTest.java</include>
</includes>
</configuration>
</plugin>
透過 Maven 執行單元測試的最短方法是執行以下命令:
$ mvn test
我們可以看到我們的測試失敗了,並出現與之前相同的錯誤!然而,使用surefire插件,修正在於設定argLine配置標籤:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.3.0</version>
<configuration>
<includes>
<include>**/*UnitTest.java</include>
</includes>
<argLine>--add-opens=java.base/java.util=ALL-UNNAMED</argLine>
</configuration>
</plugin>
我們的單元測試現在可以成功運行!
3.4.故障安全插件
我們現在將為控制器編寫整合測試:
@SpringBootTest(classes = MyApplication.class)
@AutoConfigureMockMvc
class MyControllerIntegrationTest {
@Autowired
private MockMvc mockMvc;
@Test
void whenGetLength_thenZeroIsReturned() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.get("/length"))
.andExpect(MockMvcResultMatchers.status().isOk())
.andExpect(MockMvcResultMatchers.content().string("0"));
}
}
通常,我們使用failsafe插件透過Maven運行整合測試。再次,讓我們使用最新版本的基本配置來設定它:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>3.3.0</version>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
<configuration>
<includes>
<include>**/*IntegrationTest.java</include>
</includes>
</configuration>
</plugin>
現在讓我們執行整合測試:
$ mvn verify
毫不奇怪,我們的整合測試因我們已經遇到的相同錯誤而失敗。 failsafe插件的修正與surefire插件的修正相同。我們必須使用argLine配置標籤來設定 JVM 參數:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>3.3.0</version>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
<configuration>
<includes>
<include>**/*IntegrationTest.java</include>
</includes>
<argLine>--add-opens=java.base/java.util=ALL-UNNAMED</argLine>
</configuration>
</plugin>
整合測試現在將成功運行。
4。
在本文中,我們學習了在 Maven 中執行 Java 程式碼時如何使用 JVM 參數。我們探索了兩種為建構設定全域參數的技術。然後,我們了解如何將 JVM 參數傳遞給一些最常用的插件。我們的範例並不詳盡,但一般來說,其他外掛程式的工作方式非常相似。回顧一下,我們始終可以參考插件文件來準確了解如何配置它。
與往常一樣,程式碼可以在 GitHub 上取得。