osgi應用使用橋接的方式打成war包部署在websphere上時遇到的與cxf相關的問題



原來我們的程序都是基於Equinox架構的,可是后面由於要實現打成war包在中間件中部署的需求,使用了eclipse官方提供的橋接方式實現。

橋接的部分后面有時間了我專門寫一個文章來說,不明確的臨時請參考eclipse官方文檔。這里主要說一下已經橋接成功。可是在使用CXF時遇到問題的情況。



本來在其它中間件里跑得好好的程序,一放到websphere_v8里,就各種報錯。都是與axis2有關的,可是我們的項目並沒有使用axis2。而是使用cxf。


報錯類似例如以下(我有3個環境。每一個報的錯都不同,只是都非常明顯的出現了不該出現的axis2):


java.lang.ClassCastException: org.apache.axis2.jaxws.client.proxy.JAXWSProxyHandler incompatible with org.apache.cxf.frontend.ClientProxy
	at org.apache.cxf.frontend.ClientProxy.getClient(ClientProxy.java:93)



后來查了資料發現websphere有自帶的jaxws引擎。能夠看到在$WAS_HOME/endorsed_apis下有三個jar包:

javax.j2ee.annotation.jar
jaxb-api.jar
jaxws-api.jar//version:2.2

然后在$WAS_HOME/plugins下有org.apache.axis2.jar.


比方說,你實現了MyService繼承了javax.xml.Service。

那么在Service的構造方法里我們能夠看到:

 protected Service(java.net.URL wsdlDocumentLocation, QName serviceName) {
        delegate = Provider.provider().createServiceDelegate(wsdlDocumentLocation,
                serviceName,
                this.getClass());
    }
就是這個Provider.provider()得到的Provider實現始終是axis的實現,而不是我們的cxf的實現。



一、通用方案


查詢了cxf和IBM的官方文檔。得到的解決方式例如以下:


參考

http://www-01.ibm.com/support/knowledgecenter/SS7JFU_7.0.0/com.ibm.websphere.express.doc/info/exp/ae/twbs_thirdparty.html?lang=en

http://cxf.apache.org/docs/application-server-specific-configuration-guide.html#ApplicationServerSpecificConfigurationGuide-ForWebSphere6.1.0.29+,V7andV8



1.關閉websphere自帶的jaxws引擎。這里有兩種級別的設置:


server級:


在控制台界面進入應用程序服務器 > server1 > 進程定義 > Java 虛擬機。然后在通用JVM參數中增加

-Dcom.ibm.websphere.webservices.DisableIBMJAXWSEngine=true 

或者再進入定制屬性。加入一個定制屬性name=com.ibm.websphere.webservices.DisableIBMJAXWSEngine, value=true.


針對某個app:


在你的war包的META-INF/MANIFEST.MF中增加DisableIBMJAXWSEngine:true,像這樣

Manifest-Version: 1.0
DisableIBMJAXWSEngine: true
Class-Path: 

2.設置你的應用的ClassLoader策略為Parent_Last


企業應用程序 > $YOUR_APP > 類裝入和更新檢測

把類裝入器順序設置為Parent_Last

設置Application的classloader策略


企業應用程序 > $YOUR_APP > 模塊管理 > $YOUR_MODULE ,將類裝入器順序設置為Parent_Last



最后另一個地方的類載入策略(能夠驗證一下這個是否須要設置。有些文章上沒有說這個地方):

應用程序服務器 > server1。把類裝入方式設置為Parent_Last



以上就是IBM和CXF官方提供的解決方式。



然后在網上還發現了一些其它方案:


1. 移除org.apache.axis2.jarH或移除org.apache.axis2.jar中的'META-INF/services/javax.xml.ws.spi.Provider' 

這比較暴力,並且會造成對整個WAS的影響。


2. 改用

JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
factory.setAddress(wsdlURL);
factory.setServiceClass(MyWebService.class);
MyWebService port = (MyWebService) factory.create();
//and then call ClientProxy as usual but with the object created using JaxWsProxyFactoryBean
Client client = ClientProxy.getClient(port); 

替代原來的

MyWebService ss = new   MyWebService (wsdlURL, SERVICE_NAME);
instance = ss.getTestHttpPort();
Client cxfClient = ClientProxy.getClient(instance); 

第2條我試的時候,報了MyWebService不是一個interface的錯誤.沒有詳細去跟是什么原因。


在網上的全部能找到的方式都嘗試無果之后,不得不自己分析了。


二、橋接的方式特殊的地方


JAX-WS採用了service provider interface (SPI)的機制,定義了上層的API。執行的時候再由Provider類載入不同的實現。


首先看一下JAX-WS的載入順序:

    
    
   
   
           
JAX-WS 的載入順序
javax.xml.ws.spi.Provider provider()
  • If a resource with the name of META-INF/services/javax.xml.ws.spi.Provider
    = com.sun.xml.ws.spi.ProviderImpl
  • $java.home/lib/jaxws.properties,it contains an entry whose key is javax.xml.ws.spi.Provider
  • If a system property with the name javax.xml.ws.spi.Provider
  • Default is loaded(com.sun.xml.internal.ws.spi.ProviderImpl)
javax.xml.bind.ContextFinder.find
  • jaxb.properties (key=javax.xml.bind.JAXBContext)
  • System property with name javax.xml.bind.JAXBContext
  • META-INF/services/javax.xml.bind.JAXBContext 
  • Default is loaded(com.sun.xml.internal.bind.v2.ContextFactory)
   
   
  
  
          
|_META-INF
|_services
|_ javax.xml.bind.JAXBContext (com.sun.xml.bind.v2.ContextFactory)

jaxws-api肯定是用的websphere的了,在我們已經依照官方文檔關閉了IBMJAXWSEngine和改動ClassLoader策略之后,他還是老是載入到websphere自帶的axis2。,所以推測Provider.provider()在尋找Provider的實現時。根本沒有發現我們應用中的cxf包,這跟OSGI橋接的方式相關,使用這樣的方式的同學應該了解是什么文件夾結構。

所以,解決方案是在war/WEB-INF/lib中也放入一個cxf.jar. 然后再也沒有出現axis2來困擾我們了。


這里就會產生一個問題,lib包中有一個cxf,eclipse的plugin文件夾下也有一個cxf。

那么使用的時候會出現類沖突嗎?

假設直接把eclipse的plugin文件夾下的cxf移除掉,啟動的時候肯定各種bundle依賴報錯。那么外面一個cxf,里面一個cxf究竟會不會產生沖突呢?


答案是不會。 


由於我把lib下的cxf包中的內容都刪了。僅僅剩下META-INF/services/中的幾個文件。竟然也能夠正常執行。所以能夠看出執行中載入到的類應該還都是eclipse的plugins中的cxf中的類.  推測載入cxf中的類是從equinox中的bundle的classLoader開始載入的,所以就會載入到eclipse中的plugins中的類。假設是用的Module或之上的ClassLoader來載入,那么在lib下僅僅有cxf空包,而沒有詳細的類的時候。肯定會載入不到這個類。那么既然在這樣的情況下還能載入到,就說明是從bundle的Classloader開始載入的。

只是為了保險起見。這一個步的終於方案為:

cxf中的META-INF/services文件夾拷貝出來打成一個jar包,放在war/WEB-INF/lib文件夾下.





免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM