Tôi hiểu sự khác biệt giữa thời gian chạy và thời gian biên dịch cũng như cách phân biệt giữa hai loại này, nhưng tôi không thấy cần phải phân biệt giữa thời gian biên dịch và thời gian chạy phụ thuộc.
Các khái niệm thời gian biên dịch và thời gian chạy chung và các phụ thuộc phạm vi compile
và cụ thể của Maven runtime
là hai điều rất khác nhau. Bạn không thể so sánh trực tiếp chúng vì chúng không có cùng khung: khái niệm thời gian chạy và biên dịch chung là rộng trong khi khái niệm maven compile
và runtime
phạm vi nói về cụ thể tính khả dụng / khả năng hiển thị theo thời gian: biên dịch hoặc thực thi.
Đừng quên rằng Maven là trên hết a javac
/ java
wrapper và trong Java, bạn có một đường dẫn thời gian biên dịch mà bạn chỉ định javac -cp ...
và một đường dẫn thời gian chạy mà bạn chỉ định java -cp ...
.
Sẽ không sai nếu coi compile
phạm vi Maven như một cách để thêm phần phụ thuộc vào cả trình biên dịch Java và đường dẫn lớp thời gian chạy (javac
và java
) trong khi runtime
phạm vi Maven có thể được coi là một cách để thêm một phần phụ thuộc chỉ trong lớp chạy thời gian chạy Java classppath ( javac
).
Điều tôi đang mắc kẹt là: làm thế nào một chương trình có thể không phụ thuộc vào một thứ gì đó trong thời gian chạy mà nó phụ thuộc vào trong quá trình biên dịch?
Những gì bạn mô tả không có bất kỳ mối quan hệ runtime
và compile
phạm vi nào.
Có vẻ như nhiều hơn đối với provided
phạm vi mà bạn chỉ định cho một phụ thuộc để phụ thuộc vào đó tại thời điểm biên dịch nhưng không phải trong thời gian chạy.
Bạn sử dụng nó khi bạn cần phụ thuộc để biên dịch nhưng bạn không muốn đưa nó vào thành phần được đóng gói (JAR, WAR hoặc bất kỳ thành phần nào khác) bởi vì phụ thuộc đã được cung cấp bởi môi trường: nó có thể được đưa vào máy chủ hoặc bất kỳ đường dẫn của classpath được chỉ định khi ứng dụng Java được khởi động.
Nếu ứng dụng Java của tôi sử dụng log4j, thì nó cần tệp log4j.jar để biên dịch (mã của tôi tích hợp và gọi các phương thức thành viên từ bên trong log4j) cũng như thời gian chạy (mã của tôi hoàn toàn không có quyền kiểm soát những gì xảy ra khi mã bên trong log4j .jar được chạy).
Trong trường hợp này có. Nhưng giả sử rằng bạn cần viết một mã di động dựa vào slf4j làm mặt tiền trước log4j để có thể chuyển sang triển khai ghi nhật ký khác sau này (log4J 2, logback hoặc bất kỳ thứ gì khác).
Trong trường hợp này, bạn cần chỉ định slf4j làm compile
phụ thuộc (đó là mặc định) nhưng bạn sẽ chỉ định phụ thuộc log4j làm runtime
phụ thuộc:
<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>
Bằng cách này, các lớp log4j không thể được tham chiếu trong mã đã biên dịch nhưng bạn vẫn có thể tham chiếu đến các lớp slf4j.
Nếu bạn đã chỉ định hai phần phụ thuộc cùng với compile
thời gian, thì không có gì ngăn cản bạn tham chiếu đến các lớp log4j trong mã đã biên dịch và do đó bạn có thể tạo một khớp nối không mong muốn với việc triển khai ghi nhật ký:
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>...</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>...</version>
</dependency>
Cách sử dụng phổ biến của runtime
phạm vi là khai báo phụ thuộc JDBC. Để viết mã di động, bạn không muốn mã máy khách có thể tham chiếu đến các lớp của phụ thuộc DBMS cụ thể (ví dụ: phụ thuộc PostgreSQL JDBC) nhưng bạn muốn tất cả những thứ tương tự bao gồm nó trong ứng dụng của mình vì trong thời gian chạy các lớp cần thiết để tạo API JDBC hoạt động với DBMS này.