1. 程式人生 > >關於maven依賴中的<scope>provided</scope>使用

關於maven依賴中的<scope>provided</scope>使用

ces native 設置 依賴 jar包 $1 解決 init diff

今天開發web的時候,需要用到servlet-api,於是在pom.xml中添加依賴

<dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>3.0-alpha-1</version>
        </dependency>

通過插件啟動tomcat的時候,報錯,裏面有一段是這樣的:

Caused by: java.lang.LinkageError: loader constraint violation: loader (instance of org/apache/catalina/loader/WebappClassLoader) previously initiated loading for a different type with name "javax/servlet/ServletContext"
    at java.lang.ClassLoader.defineClass1(Native Method)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:800)
    at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
    at java.net.URLClassLoader.defineClass(URLClassLoader.java:449)
    at java.net.URLClassLoader.access$100(URLClassLoader.java:71)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
技術分享圖片

產生的原因是:tomcat中也有servlet-api包,這樣,發生了沖突

解決方法:添加<scope>provided</scope>,因為provided表明該包只在編譯和測試的時候用,所以,當啟動tomcat的時候,就不會沖突了,完整依賴如下:

<dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>3.0-alpha-1</version>
            <scope>provided</scope>
        </dependency>

對於scope=compile的情況(默認scope),也就是說這個項目在編譯,測試,運行階段都需要這個artifact對應的jar包在classpath中。

而對於scope=provided的情況,則可以認為這個provided是目標容器已經provide這個artifact。換句話說,它只影響到編譯,測試階段。在編譯測試階段,我們需要這個artifact對應的jar包在classpath中,而在運行階段,假定目標的容器(比如我們這裏的liferay容器)已經提供了這個jar包,所以無需我們這個artifact對應的jar包了。

聽起來很玄乎,對吧,其實一點也不難理解。舉個scope=provided的例子。

比如說,假定我們自己的項目ProjectABC 中有一個類叫C1,而這個C1中會import這個portal-impl的artifact中的類B1,那麽在編譯階段,我們肯定需要這個B1,否則C1通不過編譯,因為我們的scope設置為provided了,所以編譯階段起作用,所以C1正確的通過了編譯。測試階段類似,故忽略。

那麽最後我們要吧ProjectABC部署到Liferay服務器上了,這時候,我們到$liferay-tomcat-home\webapps\ROOT\WEB-INF\lib下發現,裏面已經有了一個portal-impl.jar了,換句話說,容器已經提供了這個artifact對應的jar,所以,我們在運行階段,這個C1類直接可以用容器提供的portal-impl.jar中的B1類,而不會出任何問題。

實際插件的行為:

剛才我們講述的是理論部分,現在我們看下,實際插件在運行時候,是如何來區別對待scope=compile和scope=provided的情況的。

做一個實驗就可以很容易發現,當我們用maven install生成最終的構件包ProjectABC.war後,在其下的WEB-INF/lib中,會包含我們被標註為scope=compile的構件的jar包,而不會包含我們被標註為scope=provided的構件的jar包。這也避免了此類構件當部署到目標容器後產生包依賴沖突。

還有一種 scope=test 只對測試有效 一般用在junit

<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>

關於maven依賴中的<scope>provided</scope>使用