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

來源:互聯網
上載者:User

標籤:osgi   websphere   cxf   axis   


原來我們的程式都是基於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.ClientProxyat org.apache.cxf.frontend.ClientProxy.getClient(ClientProxy.java:93)



後來查了資料發現websphere有內建的jaxws引擎。可以看到在$WAS_HOME/endorsed_apis下有三個jar包:

javax.j2ee.annotation.jarjaxb-api.jarjaxws-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.0DisableIBMJAXWSEngine: trueClass-Path: 

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


公司專屬應用程式程式 > $YOUR_APP > 類裝入和更新檢測

把類裝入器順序設定為Parent_Last



公司專屬應用程式程式 > $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 JaxWsProxyFactoryBeanClient 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目錄下.




相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.