การระบุเวอร์ชัน java ใน maven - ความแตกต่างระหว่างคุณสมบัติและปลั๊กอินคอมไพเลอร์


178

ฉันไม่ได้มีประสบการณ์เกี่ยวกับ Maven มากและในขณะที่การทดสอบกับโครงการหลายโมดูลฉันเริ่มสงสัยว่าฉันจะระบุรุ่น Java สำหรับโมดูลลูกทั้งหมดของฉันใน parent maven pom ได้อย่างไร จนถึงวันนี้ฉันใช้เพียง:

<properties>
    <java.version>1.8</java.version>
</properties>

แต่เมื่อทำการวิจัยพบว่าคุณยังสามารถระบุรุ่น java ในปลั๊กอินคอมไพเลอร์ maven เช่นนั้น:

<plugins>
    <plugin>    
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
            <source>1.8</source>
            <target>1.8</target>
        </configuration>
    </plugin>
</plugins>

จากนั้นใส่สิ่งนี้ลงในแท็กการจัดการปลั๊กอินเพื่อเปิดใช้งานการใช้งานลูกปอม ดังนั้นคำถามแรกคือความแตกต่างระหว่างการตั้งค่าเวอร์ชันจาวาในคุณสมบัติและในปลั๊กอินคอมไพเลอร์ maven คืออะไร?

ฉันไม่พบคำตอบที่ชัดเจน แต่ในระหว่างการวิจัยฉันพบว่าคุณยังสามารถระบุเวอร์ชันจาวาด้วยวิธีนี้:

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

ซึ่งแนะนำให้คอมไพเลอร์ปลั๊กอินมีแม้ว่าฉันไม่ชัดเจนประกาศ กำลังรันเอาต์พุตแพ็กเกจ mvn ด้วย

maven-compiler-plugin:3.1:compile (default-compile) @ testproj ---

และปลั๊กอินอื่น ๆ ที่ฉันไม่ได้ประกาศ ดังนั้นปลั๊กอินเหล่านั้นจึงเป็นค่าเริ่มต้นส่วนที่ซ่อนอยู่ของ maven pom? มีความแตกต่างระหว่างการตั้งค่าแหล่งที่มา / เป้าหมายในคุณสมบัติและในองค์ประกอบการกำหนดค่าปลั๊กอิน maven หรือไม่?

คำถามอื่น ๆ คือ - ควรใช้วิธีใด (และเมื่อใดหากไม่เท่ากัน) อันไหนที่ดีที่สุดสำหรับโครงการหลายโมดูลและจะเกิดอะไรขึ้นถ้ารุ่นจาวาที่ระบุใน pom แตกต่างจากเวอร์ชันที่ชี้ใน JAVA_HOME

คำตอบ:


289

จะระบุเวอร์ชั่นของ JDK ได้อย่างไร?

1) <java.version>ไม่ได้อ้างอิงในเอกสาร Maven
มันเป็นคุณสมบัติเฉพาะของ Spring Boot
อนุญาตให้ตั้งค่าซอร์สและเวอร์ชัน Java เป้าหมายด้วยเวอร์ชันเดียวกันเช่นนี้เพื่อระบุ java 1.8 สำหรับทั้งสอง:

<properties>
     <java.version>1.8</java.version>
</properties>   

รู้สึกอิสระที่จะใช้มันหากคุณใช้ Spring Boot

2) การใช้maven-compiler-pluginหรือmaven.compiler.source/ maven.compiler.targetคุณสมบัติเพื่อระบุsourceและtargetจะเทียบเท่า

<plugins>
    <plugin>    
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
            <source>1.8</source>
            <target>1.8</target>
        </configuration>
    </plugin>
</plugins>

และ

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

เทียบเท่าตามเอกสาร Maven ของปลั๊กอินคอมไพเลอร์ ตั้งแต่<source>และ<target>องค์ประกอบในการกำหนดค่าคอมไพเลอร์ใช้คุณสมบัติmaven.compiler.sourceและmaven.compiler.targetหากมีการกำหนดไว้

แหล่ง

-sourceอาร์กิวเมนต์สำหรับการคอมไพเลอร์ Java ค่าเริ่มต้นคือ
สถานที่ให้บริการผู้ใช้: 1.6
maven.compiler.source

เป้า

-targetอาร์กิวเมนต์สำหรับการคอมไพเลอร์ Java ค่าเริ่มต้นคือ
สถานที่ให้บริการผู้ใช้: 1.6
maven.compiler.target

เกี่ยวกับค่าเริ่มต้นสำหรับการsourceและ targetทราบว่า ตั้งแต่3.8.0ของคอมไพเลอร์ Maven ค่าเริ่มต้นที่มีการเปลี่ยนแปลงจาก1.51.6การ

3) maven-compiler-plugin 3.6และรุ่นที่ใหม่กว่าเป็นวิธีใหม่:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.8.0</version>
    <configuration>
        <release>9</release>
    </configuration>
</plugin>

คุณสามารถประกาศเพียง:

<properties>
    <maven.compiler.release>9</maven.compiler.release>
</properties>

แต่ในเวลานี้มันจะไม่ทำงานเป็นmaven-compiler-pluginเวอร์ชันเริ่มต้นที่คุณใช้ไม่พึ่งพาเวอร์ชันล่าสุดที่เพียงพอ

releaseอาร์กิวเมนต์Maven บ่งบอกถึง release: ตัวเลือกมาตรฐาน JVM ใหม่ที่เราสามารถผ่านจาก Java 9:

คอมไพล์ต่อต้าน API สาธารณะที่ได้รับการสนับสนุนและจัดทำเป็นเอกสารสำหรับ VM รุ่นที่ระบุ

วิธีนี้จัดเตรียมวิธีมาตรฐานในการระบุเวอร์ชันเดียวกันสำหรับตัวเลือกsourcethe targetและbootstrapJVM
โปรดทราบว่าการระบุbootstrapเป็นวิธีปฏิบัติที่ดีสำหรับการรวบรวมข้ามและจะไม่เจ็บถ้าคุณไม่ได้ทำการรวบรวมข้ามเช่นกัน


วิธีใดดีที่สุดในการระบุรุ่น JDK

อนุญาตวิธีแรก ( <java.version>) เฉพาะเมื่อคุณใช้ Spring Boot

สำหรับ Java 8 และต่ำกว่า:

เกี่ยวกับอีกสองวิธี: การประเมินค่าmaven.compiler.source/ maven.compiler.targetคุณสมบัติหรือการใช้maven-compiler-pluginคุณสามารถใช้อย่างใดอย่างหนึ่ง มันไม่มีอะไรเปลี่ยนแปลงในข้อเท็จจริงเนื่องจากในที่สุดทั้งสองโซลูชันจะใช้คุณสมบัติเดียวกันและกลไกเดียวกันนั่นคือปลั๊กอินคอมไพเลอร์ maven core

ถ้าคุณไม่จำเป็นต้องระบุคุณสมบัติหรือลักษณะการทำงานอื่นนอกเหนือจาก Java เวอร์ชันในปลั๊กอินคอมไพเลอร์การใช้วิธีนี้เหมาะสมกว่าเนื่องจากมีความกระชับมากกว่านี้:

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

จาก Java 9:

releaseอาร์กิวเมนต์ (จุดที่สาม) เป็นวิธีการที่จะต้องพิจารณาอย่างยิ่งถ้าคุณต้องการที่จะใช้รุ่นเดียวกันสำหรับแหล่งที่มาและเป้าหมายที่

จะเกิดอะไรขึ้นหากรุ่นแตกต่างกันระหว่าง JDK ใน JAVA_HOME และรุ่นใดที่ระบุใน pom.xml

มันไม่ได้เป็นปัญหาถ้า JDK อ้างอิงโดยJAVA_HOMEเข้ากันได้กับรุ่นที่ระบุไว้ใน pom แต่เพื่อให้แน่ใจว่าดีกว่าข้ามรวบรวมความเข้ากันได้คิดเกี่ยวกับการเพิ่มbootstrapตัวเลือก JVM กับเป็นค่าเส้นทางของrt.jarของtargetรุ่น

สิ่งสำคัญที่จะต้องพิจารณาคือว่าsourceและtargetรุ่นในการกำหนดค่า Maven ไม่ควรจะดีกว่ารุ่น JDK JAVA_HOMEอ้างอิงโดย
JDK รุ่นเก่าไม่สามารถคอมไพล์ด้วยเวอร์ชันที่ใหม่กว่าได้เนื่องจากไม่ทราบสเปคของมัน

ที่จะได้รับข้อมูลเกี่ยวกับแหล่งที่มาของเป้าหมายและปล่อยรุ่นที่ได้รับการสนับสนุนตามที่ใช้ JDK โปรดดูที่คอมไพล์ Java: แหล่งเป้าหมายและปล่อยรุ่นที่สนับสนุน


จัดการกับกรณีของ JDK ที่อ้างอิงโดย JAVA_HOME ไม่เข้ากันได้กับเป้าหมาย java และ / หรือรุ่นที่มาที่ระบุใน pom อย่างไร

ตัวอย่างเช่นถ้าคุณJAVA_HOMEอ้างถึง JDK 1.7 และคุณระบุ JDK 1.8 เป็นแหล่งที่มาและเป้าหมายในการกำหนดค่าคอมไพเลอร์ของ pom.xml ของคุณมันจะมีปัญหาเพราะตามที่อธิบายไว้ JDK 1.7 ไม่ทราบวิธีการรวบรวม .
จากมุมมองของมันมันเป็นรุ่น JDK ที่ไม่รู้จักตั้งแต่เปิดตัวหลังจากนั้น
ในกรณีนี้คุณควรกำหนดค่าปลั๊กอินคอมไพเลอร์ Maven เพื่อระบุ JDK ด้วยวิธีนี้:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <configuration>
        <source>1.8</source>
        <target>1.8</target>
        <compilerVersion>1.8</compilerVersion>      
        <fork>true</fork>
        <executable>D:\jdk1.8\bin\javac</executable>                
    </configuration>
</plugin>

คุณอาจมีรายละเอียดเพิ่มเติมในตัวอย่างที่มี Maven คอมไพเลอร์ปลั๊กอิน


ไม่มีการถาม แต่กรณีที่อาจมีความซับซ้อนมากขึ้นคือเมื่อคุณระบุแหล่งที่มา แต่ไม่ได้กำหนดเป้าหมาย อาจใช้เวอร์ชันที่แตกต่างในเป้าหมายตามเวอร์ชันต้นทาง กฎระเบียบที่มีเฉพาะ: คุณสามารถอ่านเกี่ยวกับพวกเขาในส่วนที่ตัวเลือกข้ามรวบรวม


เหตุใดปลั๊กอินคอมไพเลอร์จึงถูกติดตามในเอาต์พุตเมื่อเรียกใช้งานpackageเป้าหมายMaven แม้ว่าคุณจะไม่ได้ระบุไว้ใน pom.xml

ในการรวบรวมรหัสของคุณและโดยทั่วไปในการทำงานทั้งหมดที่จำเป็นสำหรับเป้าหมาย Maven Maven ต้องการเครื่องมือ ดังนั้นจึงใช้ปลั๊กอิน Maven หลัก (คุณรู้จักปลั๊กอินหลัก Maven โดยตนgroupId: org.apache.maven.plugins) เพื่อดำเนินงานที่ต้องการ: ปลั๊กอินคอมไพเลอร์สำหรับการเรียนการรวบรวมปลั๊กอินสำหรับการดำเนินการทดสอบการทดสอบและอื่น ๆ สำหรับ ... ดังนั้นแม้ว่าคุณจะทำไม่ได้ ประกาศปลั๊กอินเหล่านี้พวกเขาจะผูกพันกับการดำเนินการของวงจรชีวิต Maven
ที่ root dir ของโครงการ Maven ของคุณคุณสามารถรันคำสั่ง: mvn help:effective-pomเพื่อให้ pom สุดท้ายใช้อย่างมีประสิทธิภาพ คุณสามารถดูข้อมูลอื่น ๆ ปลั๊กอินที่แนบโดย Maven (ระบุหรือไม่อยู่ใน pom.xml ของคุณ) ด้วยเวอร์ชันที่ใช้การกำหนดค่าและเป้าหมายที่ดำเนินการในแต่ละช่วงของวงจรชีวิต

ในผลลัพธ์ของmvn help:effective-pomคำสั่งคุณสามารถเห็นการประกาศของปลั๊กอินหลักเหล่านี้ใน<build><plugins>องค์ประกอบตัวอย่างเช่น:

...
<plugin>
   <artifactId>maven-clean-plugin</artifactId>
   <version>2.5</version>
   <executions>
     <execution>
       <id>default-clean</id>
       <phase>clean</phase>
       <goals>
         <goal>clean</goal>
       </goals>
     </execution>
   </executions>
 </plugin>
 <plugin>
   <artifactId>maven-resources-plugin</artifactId>
   <version>2.6</version>
   <executions>
     <execution>
       <id>default-testResources</id>
       <phase>process-test-resources</phase>
       <goals>
         <goal>testResources</goal>
       </goals>
     </execution>
     <execution>
       <id>default-resources</id>
       <phase>process-resources</phase>
       <goals>
         <goal>resources</goal>
       </goals>
     </execution>
   </executions>
 </plugin>
 <plugin>
   <artifactId>maven-compiler-plugin</artifactId>
   <version>3.1</version>
   <executions>
     <execution>
       <id>default-compile</id>
       <phase>compile</phase>
       <goals>
         <goal>compile</goal>
       </goals>
     </execution>
     <execution>
       <id>default-testCompile</id>
       <phase>test-compile</phase>
       <goals>
         <goal>testCompile</goal>
       </goals>
     </execution>
   </executions>
 </plugin>
  ...

คุณสามารถมีข้อมูลเพิ่มเติมเกี่ยวกับเรื่องนี้ในการแนะนำของ lifeycle Maven ในเอกสาร

อย่างไรก็ตามคุณสามารถประกาศปลั๊กอินเหล่านี้เมื่อคุณต้องการกำหนดค่าด้วยค่าอื่นเป็นค่าเริ่มต้น (ตัวอย่างเช่นคุณทำเมื่อคุณประกาศปลั๊กอิน maven-compiler ใน pom.xml ของคุณเพื่อปรับรุ่น JDK ที่จะใช้) หรือเมื่อคุณ ต้องการเพิ่มการดำเนินการปลั๊กอินบางอย่างที่ไม่ได้ใช้เป็นค่าเริ่มต้นในวงจรชีวิต Maven


ขอบคุณสำหรับคำอธิบายมากมายตอนนี้มันชัดเจนสำหรับฉันมาก นอกจากนี้เกี่ยวกับ <java.version> - ฉันเคยเห็นสิ่งนี้ในข้อมูลโค้ดบางอันบางทีนั่นอาจเป็นคุณสมบัติที่กำหนดเองและฉันคิดว่ามันผิดวิธีที่จะประกาศรุ่น Java จะติดกับ<maven.compiler.x>คุณสมบัติต่อจากนี้ไป
Plebejusz

คุณยินดีด้วยความยินดี :) เริ่มแรกมันไม่ได้ตั้งใจที่จะพัฒนามาก แต่เมื่อฉันเริ่มฉันไม่สามารถหยุด :) สำหรับ `<java.version>` มันมีโอกาสมาก เห็นคุณและ Maven ดี!
davidxxx

1
" ไม่ใช่ปัญหาหาก JDK ของ JAVA_HOME ของคุณเข้ากันได้กับรุ่นที่ระบุใน pom " นี่ไม่ใช่ (จำเป็น) จริงให้ตรวจสอบเธรดสแต็ค
โอเวอร์โฟลว์

2
@ Robin A. Meade ขอบคุณสำหรับคำติชม ฉันใช้สปริงบู๊ท แต่ฉันไม่รู้ โดยส่วนตัวแล้วฉันไม่ได้พบว่ามันมาตรฐานพอที่จะใช้หรืออ้างอิงเป็นสิ่งที่ใช้ Spring boot มีบางสิ่งที่น่าสนใจ แต่ในบางกรณีคุณสมบัติของมันนั้นไม่น่าเชื่อถือ การแทนที่ชื่อของคุณสมบัติ maven มาตรฐานเพื่อไม่เติมทั้งแหล่งที่มาและเป้าหมาย jdk จะปรากฏขึ้นเป็นแนวคิดที่ไม่ดีเนื่องจากมีการดำเนินการเพียงครั้งเดียวสำหรับแอปพลิเคชัน คุณสูญเสียมาตรฐานในการสำรองบรรทัด XML อย่างง่ายในแอปพลิเคชันของคุณ ว้าว! ช่างเป็นความคิด ...
davidxxx

1
@ MasterJoe2 คุณพบมันในเอกสาร javac อย่างเป็นทางการของรุ่น 10: docs.oracle.com/javase/10/tools/javac.htm#JSWOR627 ฉันแบ่งคำตอบนั้นออกเป็นสองส่วนเนื่องจากมันใหญ่เกินไปคุณสามารถดูได้ที่: stackoverflow.com/questions/51692748/…
davidxxx

3

วิธีการแก้ปัญหาข้างต้นไม่ได้ผลสำหรับฉันทันที ดังนั้นฉันจึงทำดังต่อไปนี้: -

  1. ที่เพิ่ม

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

    ใน pom.xml

  2. ไปProject Properties > Java Build Pathแล้วออกระบบห้องสมุด JRE JRE1.5ซึ่งชี้ไปที่

  3. บังคับให้อัพเดทโครงการ


เวอร์ชันใดที่คุณระบุสำหรับ Java 10 และสูงกว่า มันคือ 10 หรือ 1.10
MasterJoe2

@ MasterJoe2 จาก java 9 และเวอร์ชันที่สูงกว่าคุณต้องเขียนหมายเลขเวอร์ชั่นตามที่เป็น (<version> 10 </version>) และสำหรับเวอร์ชั่นด้านล่างคุณต้องเพิ่ม 1 ไว้ข้างหน้าเวอร์ชัน (<version> 1.5 </version>)
ikbel benab

0

พิจารณาทางเลือก:

<properties>
    <javac.src.version>1.8</javac.src.version>
    <javac.target.version>1.8</javac.target.version>
</properties>

มันควรจะเหมือนกันmaven.compiler.source/maven.compiler.targetแต่วิธีแก้ปัญหาด้านบนใช้ได้ผลกับฉันไม่เช่นนั้นอันที่สองจะได้ข้อมูลจำเพาะของผู้ปกครอง (ฉันมี matrioska ของ. pom)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.