ฉันเข้าใจความแตกต่างระหว่างรันไทม์และเวลาคอมไพล์และวิธีแยกความแตกต่างระหว่างทั้งสอง แต่ฉันไม่เห็นว่าจำเป็นต้องสร้างความแตกต่างระหว่างการอ้างอิงเวลาคอมไพล์และรันไทม์
แนวคิดทั่วไปเกี่ยวกับเวลาคอมไพล์และรันไทม์และการอ้างอิงเฉพาะของ Maven compile
และruntime
ขอบเขตเป็นสองสิ่งที่แตกต่างกันมาก คุณไม่สามารถเปรียบเทียบได้โดยตรงเนื่องจากสิ่งเหล่านี้ไม่มีเฟรมเดียวกัน: แนวคิดการคอมไพล์และรันไทม์ทั่วไปนั้นกว้างในขณะที่แนวคิดmaven compile
และruntime
ขอบเขตนั้นเกี่ยวกับความพร้อมใช้งาน / การมองเห็นที่อ้างอิงตามเวลา: การรวบรวมหรือการดำเนินการ
อย่าลืมว่า Maven อยู่เหนือทั้งหมดjavac
/ java
เสื้อคลุมและใน Java คุณมี classpath รวบรวมเวลาที่คุณระบุมีjavac -cp ...
และ classpath java -cp ...
รันไทม์ที่คุณระบุด้วย
ไม่ผิดที่จะพิจารณาcompile
ขอบเขตMaven เป็นวิธีเพิ่มการพึ่งพาทั้งใน Java compile และ runtime classppath (javac
และjava
) ในขณะที่runtime
ขอบเขตMaven สามารถมองเห็นได้ว่าเป็นวิธีเพิ่มการพึ่งพาเฉพาะใน Java runtime classppath ( javac
)
สิ่งที่ฉันสำลักคือ: โปรแกรมจะไม่ขึ้นอยู่กับบางสิ่งบางอย่างในรันไทม์ที่ขึ้นอยู่ระหว่างการคอมไพล์ได้อย่างไร
สิ่งที่คุณอธิบายไม่มีความสัมพันธ์runtime
และcompile
ขอบเขตใด ๆ
ดูเหมือนprovided
ว่าขอบเขตที่คุณระบุสำหรับการอ้างอิงจะขึ้นอยู่กับขอบเขตนั้นในเวลาคอมไพล์ แต่ไม่ใช่ที่รันไทม์
คุณใช้มันตามที่คุณต้องการการอ้างอิงในการคอมไพล์ แต่คุณไม่ต้องการรวมไว้ในคอมโพเนนต์แบบแพ็กเกจ (JAR, WAR หรืออื่น ๆ ) เนื่องจากการอ้างอิงนั้นจัดเตรียมไว้แล้วโดยสภาพแวดล้อม: สามารถรวมไว้ในเซิร์ฟเวอร์หรือใด ๆ พา ธ ของคลาสพา ธ ที่ระบุเมื่อแอ็พพลิเคชัน Java เริ่มทำงาน
หากแอป Java ของฉันใช้ log4j แสดงว่าต้องใช้ไฟล์ log4j.jar เพื่อที่จะคอมไพล์ (รหัสของฉันที่รวมเข้ากับและเรียกใช้เมธอดสมาชิกจากภายใน log4j) รวมทั้งรันไทม์ (รหัสของฉันไม่สามารถควบคุมสิ่งที่เกิดขึ้นได้อย่างแน่นอนเมื่อโค้ดภายใน log4j .jar รัน)
ในกรณีนี้ใช่ แต่สมมติว่าคุณต้องเขียนโค้ดแบบพกพาที่อาศัย slf4j เป็นส่วนหน้าของ log4j เพื่อให้สามารถเปลี่ยนไปใช้การบันทึกอื่นในภายหลัง (log4J 2, logback หรืออื่น ๆ )
ในกรณีนี้ในคุณ pom คุณต้องระบุ slf4j เป็นการcompile
อ้างอิง (เป็นค่าเริ่มต้น) แต่คุณจะระบุการอ้างอิง log4j เป็นการruntime
อ้างอิง:
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>...</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>...</version>
<scope>runtime</scope>
</dependency>
ด้วยวิธีนี้คลาส log4j ไม่สามารถอ้างอิงในโค้ดที่คอมไพล์ได้ แต่คุณจะยังคงสามารถอ้างถึงคลาส slf4j ได้
หากคุณระบุการอ้างอิงทั้งสองด้วยcompile
เวลาจะไม่มีสิ่งใดขัดขวางคุณจากการอ้างอิงคลาส log4j ในโค้ดที่คอมไพล์และคุณสามารถสร้างการเชื่อมต่อที่ไม่พึงปรารถนากับการใช้งานการบันทึก:
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>...</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>...</version>
</dependency>
การใช้runtime
ขอบเขตทั่วไปคือการประกาศการอ้างอิง JDBC ในการเขียนโค้ดแบบพกพาคุณไม่ต้องการให้โค้ดไคลเอ็นต์อ้างถึงคลาสของการพึ่งพา DBMS ที่เฉพาะเจาะจง (ตัวอย่างเช่น PostgreSQL JDBC dependency) แต่คุณต้องการให้สิ่งเดียวกันทั้งหมดรวมไว้ในแอปพลิเคชันของคุณในขณะรันไทม์คลาสจำเป็นในการสร้าง JDBC API ทำงานกับ DBMS นี้