2011-08-15 45 views
89

我理解運行時間和編譯時間之間的區別,以及如何區分這兩者,但我不認爲需要區分編譯時和運行時依賴關係程序在編譯期間是否依賴庫而不是運行時?

我在ch咽的是這樣的:程序如何不依賴於在編譯期間依賴的運行時?如果我的Java應用程序使用log4j,那麼它需要log4j.jar文件來編譯(我的代碼與log4j內部的成員方法集成和調用)以及運行時(我的代碼完全無法控制一旦log4j內部的代碼發生了什麼.jar運行)。

我正在閱讀依賴解析工具,如Ivy和Maven,這些工具明確地區分了這兩種依賴關係。我只是不明白它的需要。

任何人都可以給出一個簡單的「國王英語」類型的解釋,最好有一個實際的例子,即使像我這樣一個可憐的sap能理解?

+2

您可以使用反射,並使用編譯時不可用的類。認爲「插件」。 –

回答

53

運行時通常需要編譯時間依賴性。在maven中,一個compile作用域依賴項將被添加到運行時的類路徑中(例如,在戰爭中它們將被複制到WEB-INF/lib中)。

然而,這並不是嚴格要求;例如,我們可能會針對某個API進行編譯,使其成爲編譯時依賴項,但在運行時包含一個也包含該API的實現。

可能存在項目需要某種依賴性進行編譯,但實際上並不需要相應代碼的情況,但這些情況很少見。

另一方面,包括編譯時不需要的運行時依賴關係是非常常見的。例如,如果您正在編寫Java EE 6應用程序,則可以針對Java EE 6 API進行編譯,但在運行時可以使用任何Java EE容器;它是提供實現的容器。

使用反射可以避免編譯時依賴性。例如,可以使用Class.forName加載JDBC驅動程序,並且可以通過配置文件對實際加載的類進行配置。

+15

關於Java EE API--不是說「提供」依賴範圍的用途是什麼? – Kevin

+11

一個需要編譯依賴但不需要運行時的例子是lombok(www.projectlombok.org)。該jar用於在編譯時轉換java代碼,但在運行時完全不需要。指定範圍「提供」會導致jar不包含在war/jar中。 – Kevin

+1

@Kevin好的,'provided'範圍增加了一個編譯時間依賴關係,而不會增加運行時依賴關係,以期望依賴將在運行時以其他方式(例如容器中的共享庫)在運行時提供。另一方面,'runtime'增加了一個運行時依賴,而不會使其成爲編譯時間依賴。 – Artefacto

8

在編譯時需要在運行時可能需要的依賴關係。然而,許多庫運行時沒有所有可能的依賴關係。即可以使用四個不同的XML庫的庫,但只需要一個工作。

許多圖書館,依次需要其他圖書館。這些庫在編譯時不需要,但在運行時需要。即代碼實際運行時。

+0

你能否給我們這樣的庫的例子,這些庫在編譯時不需要,但是在運行時會需要嗎? – Cristiano

+0

@Cristiano所有的JDBC庫都是這樣的。也是實現標準API的庫。 –

4

一般而言,如果運行時和編譯時間依賴性完全相同,那麼這是理想的情況。

我會給你2個例子,當這個規則是不正確的。

如果類A依賴B類依賴於C類依賴於d類,其中A是你的類和B,C和d是從你只需要在編譯的時候,你B和C不同的第三方庫類在運行時也需要D。 程序經常使用動態類加載。在這種情況下,您不需要在編譯時使用庫動態加載的類。此外,庫經常選擇在運行時使用哪個實現。例如,SLF4J或Commons Logging可以在運行時更改目標日誌實現。在編譯時你只需要SSL4J本身。

,當你需要在編譯時比在運行時更加依賴相反的例子。 認爲您正在開發必須在不同環境或操作系統中工作的應用程序。在編譯時您需要所有特定於平臺的庫,並且在運行時只需要當前環境所需的庫。

我希望我的解釋有所幫助。

+0

您能否在編譯時詳細說明爲什麼需要C?我得到的印象(來自http://stackoverflow.com/a/7257518/6095334)編譯時是否需要C取決於(B)A引用的方法和字段。 – Hervian

0

在編譯的時候,你能夠合約/你是從你的依賴預期的API。 (例如:在這裏您只需簽署與寬帶互聯網提供商簽訂的合同) 在運行時,實際上您正在使用依賴關係。 (例如:在這裏,你實際上是在使用寬帶上網)

2

剛剛遇到問題,回答你的問題。 servlet-api.jar是我的web項目中的一個臨時依賴項,並且在編譯時和運行時都需要。但是我的Tomcat庫中還包含servlet-api.jar

這裏的解決方案是使maven中的servlet-api.jar僅在編譯時可用,並且不打包在我的war文件中,以便它不會與包含在我的Tomcat庫中的servlet-api.jar衝突。

我希望這解釋了編譯時間和運行時依賴。

+2

您的示例對於給定的問題實際上是不正確的,因爲它解釋了'compile'和'provided'作用域之間的區別,而不是'compile'和'runtime'之間的區別。 「編譯範圍」在編譯時都需要,並且打包在您的應用程序中。 '只提供範圍'只在編譯時需要,但不包含在你的應用中,因爲它是由其他方式提供的,例如它已經在Tomcat服務器中。 – MJar

+1

嗯,我認爲這是一個很好的例子,因爲問題是關於編譯時和運行時_dependencies_而不是關於'compile'和'runtime' _maven scopes_。提供的範圍是maven處理運行時包中不包含編譯時依賴的情況的方式。 –

13

每個Maven的依賴性的涵蓋範圍定義了類路徑依賴性可以用。

當您創建一個項目一個JAR,依賴不會被生成的神器捆綁;它們僅用於編譯。 (不過,你仍然可以行家包括在建罐子的依賴性,請參閱:Including dependencies in a jar with Maven

當你使用Maven創建WAR或EAR文件,你可以配置Maven捆綁在生成的構件依賴關係,並您也可以使用提供的範圍將其配置爲從WAR文件中排除某些依賴項。

最常見的範圍 - 編譯範圍 - 表示該依賴性是提供給您的項目在編譯classpath中,單元測試的編譯和執行類路徑,當你執行你的應用程序的最終運行時類路徑。在Java EE Web應用程序中,這意味着依賴項會被複制到已部署的應用程序中。然而,在一個.jar文件,依賴關係將不會被包括在編譯範圍..

運行範圍表明依賴是提供給您的項目在單元測試執行和運行時執行類路徑, 但不像編譯範圍之當您編譯應用程序或其單元測試時,不可用。 運行時依賴項被複制到已部署的應用程序中,但在編譯期間不可用!這對確保您不會錯誤地依賴特定圖書館很有幫助。(例如,請參閱:http://www.tugay.biz/2016/12/apache-commons-logging-log4j-maven.html

最後,提供的範圍表示您的應用程序執行的容器爲您提供依賴關係。在Java EE應用程序中,這意味着依賴項已經在Servlet容器或應用程序服務器的類路徑中,並且未被複制到已部署的應用程序中。這也意味着你需要這個依賴項來編譯你的項目。

+1

很好的答案,並有明確的解釋。對於新手或依賴管理的新手來說,答案非常明確。 –

相關問題