首先要說說Weblogic的classloading的機制(不一樣的Applicaiton Server,classloading的方式各有不一樣)。簡而言之,weblogic默認狀況下采用的是parent first的方式。但這個parent first,是有「講究」(tricky)的。 java
1。父類加載器和子類加載器之間的關係相似於Java中,父類和子類之間的對象關係。 web
2。Weblogic會將全部load到的class緩存到cache中。(子類classloader能看到父類classloader加載到cache中的class) 緩存
默認狀況下,當咱們的應用程序(ear,war)運行時,會先去cache中查找class,若是找不到。就去System Classpath loader 裏去找class。若是System Classpath loader裏能找到你須要的類,那麼很差意思,你在ear和war包裏包含的class就沒用了。 app
若是System ClassPath Loader找不到,接下來去ear的class path裏找,接着去EJB class path裏找,最後到war的class path裏找。一旦找到了該類,就會load起這個類,並將該類放入cache中。 webapp
上面的描述,沒什麼奇怪,但須要注意的是下面的狀況。當應用程序執行時,classloader須要的類還未在classloader裏存在。默認狀況下,此時classloader會由上至下從class path裏找,也就是說先去System和Application的class path裏找,而不是先向war的class path裏找。因此,這種狀況下,若是application的class path裏能找到所須要的class,那麼就算war的class path裏有一樣的class,war裏的class是不會被load到的。 spa
假設狀況1:(只在webapp裏有class A) xml
No Class A in current class loader cache -> Find System class path (Not found class A) -> Find Application class path (Not found class A) -> Find EJB class path (Not found class A) -> Find WebApp class loader (Found class A) 對象
假設狀況2:(在application和webapp裏都有class A) blog
No Class A in current class loader cache -> Find System class path (Not found class A) -> Find Application class path (Found class A) ssl
實際案例:
前幾天,有同事用到一個第三方類庫wsdl4j.jar,並該類庫放在在Webapp的lib目錄裏。可是系統運行時,老是報類庫版本不對的錯誤。問題就是在於,以前該項目在Application的class path裏已經存在該類庫了(給其餘的war用),並且application class path裏的類庫和war裏用的是不一樣的版本。
app.ear
|----->lib
|-->wsdl4j.jar
|------>a.war (using wsdl4j.jar in ear/lib)
|------>b.war (using wsdl4j.jar in ear/lib)
|------>c.war (using wsdl4j.jar in war/lib)
|---->WEB-INF
|---->lib
|--->wsdl4j.jar
解決方法:
weblogic提供了一個標籤<prefer-web-inf-classes>,這個標籤默認是false的,只要設置這個標籤爲true,就可讓WEB-INF裏的類先被load到了。
特殊案例:(當第三方jar和weblogic.jar有衝突)
項目中使用CXF的webservice,CXF裏有本身的javax.jws.*實現,而weblogic.jar裏也有相似實現,Weblogic啓動的時候彷佛已經把weblogic.jar裏的類都load進所謂的system classpath classloader了,程序在使用javax.jws.*的類時,類已經被system classpath classloader加載了,因此就算使用<prefer-web-inf-classes>標籤也沒有用。CXF老是用不上本身的javax.jws.*。
解決方法:
根據weblogic的官方文檔,只要是在$CLASSPATH裏的jar包都會在weblogic啓動的時候load起來,存入「system classpath classloader」的cache裏,因此程序運行時,classloader先從cache裏找class,也就找到weblogic.jar裏的javax.jws.*,因此永遠不會嘗試查找CXF裏的javax.jws.*了。weblogic9之後提供了一個新的標籤<prefer-application-packages>。用這個新標籤可以讓應用程序遇到javax.jws.*時,程序會直接到指定的ear的application class loader裏找類,而不使用在「system classpat classloader」裏的class。
大部分狀況下,使用<prefer-web-inf-classes>,應該能解決classloading的問題,在<prefer-web-inf-classes>不生效的時候,就考慮使用<prefer-application-packages>。在網上還有人提到,同時使用這兩個標籤(一個在weblogic.xml裏設,另外一個在weblogic-application.xml在設)時,<prefer-web-inf-classes>的配置無效,這個問題還有待考證。