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

企业应用程序 > $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目录下.

osgi应用使用桥接的方式打成war包部署在websphere上时遇到的与cxf相关的问题,布布扣,bubuko.com

时间: 2024-09-30 14:43:58

osgi应用使用桥接的方式打成war包部署在websphere上时遇到的与cxf相关的问题的相关文章

Web项目打成war包部署到tomcat时报MySQL Access denied for user 'root'@'localhost' (using password: YES)错误解决方案

Web项目使用使用root账号root密码进行部署,通过Eclipse加载到Tomcat服务器可以发布成功,打成war包放到tomcat的webapps目录无法发布成功,报错: jdbc.properties涉及Mysql配置: 错误很明显,与MySQL密码有关,但是两种方式部署项目使用的jdbc.properties配置文件是一样的.所以肯定不是密码不对引起的,只好找度娘,O(∩_∩)O哈哈~. 网上大部分帖通过运行mysql -u root -p命令登录时也会报这个错误,所以,我就尝试这种方

SpringBoot之打成war包部署到Tomcat

正常情况下SpringBoot项目是以jar包的形式,正常情况下SpringBoot项目是以jar包的形式,并且SpringBoot是内嵌Tomcat服务器,所以每次重新启动都是用的新的Tomcat服务器.正因如此,也出现了一个问题:    上传到项目的文件,如果是保存在项目中的,那么重启过后文件就会丢失.比如我们上传了一个头像,重启项目后,这个头像就没了.而如果将文件保存在本地磁盘中的话,html中标签没办法获取(当然,企业项目中一般是有专门的图片服务器的).因此,我们才需要将SpringBo

Web项目打成war包部署Tomcat时运行startup.bat直接闪退部署失败解决方案

即上篇通过将web项目打成war包部署到Tomcat服务器,解决mysql问题后,又出现了新问题,真是一波三折,所以将解决过程分享给大家,希望能帮助到小伙伴们~ 将打好的war包拷贝到Tomcat的webapps目录,然后在Tomcat的bin目录找到startup.bat批处理文件,直接双击执行,结果运行几秒后直接闪退,顿时有种不好的预感,在浏览器访问web项目,结果连localhost:8080都无法访问,web项目未发布成功,一脸懵逼~ 没有日志看不到为啥发布不成功额,想了想,可以稍微修改

将web项目打成war包部署在tomcat步骤

1.将自己的项目打成war包. 2.将打包好的war复制到${tomcat.home}/webapps项目下. 3.在${tomcat.hom}/conf目录下打开server.xml文件,找到Host节点,在Host节点下添加: <Context docBase="D:\Program Files\Apache Software Foundation\Tomcat 6.0\webapps\Products.war" path="/Products" relo

使用idea创建springboot项目并打成war包发布到tomcat8上

1.将pom.xml中的打包方式修改为war <groupId>com.borya</groupId> <artifactId>Project</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> 2.在pom.xml中添加依赖,将scope状态修改为provided <dependency> <gr

我爱Java系列之---【SpringBoot打成war包部署】

1.把下面这句话放入pom.xml中,放上边 <packaging>war</packaging> 2.war包要部署到tomcat服务器中,而springboot中自带了一个,这时候要去掉. <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclus

idea将web项目打成war包放在tomcat/webapps上运行

1.进入Project Structure 或者 file -> Project Structure 或者 快捷键ctrl+alt+shift+s 2.选中Artifacts 3.点加号,然后如图 4.war包的默认输出路径 5.点击+号 -> 选择Directory -> 选择web项目根路径 6.在/WEB-INF/classes目录下, 生成编译后的class文件 7.点击ok 8.点击[Build]->[BuildArtifacts]->[Build]菜单, 找到自己

记录一次SpringBoot打成war包部署到tomcat启动报错

启动时,报错信息如下: 28-Sep-2018 16:55:41.567 严重 [localhost-startStop-1] org.apache.catalina.core.StandardContext.startInternal Error during ServletContainerInitializer processing javax.servlet.ServletException: Failed to instantiate WebApplicationInitializer

eclipse利用maven自动打war包部署到tomcat7上

环境: eclipse 版本 Eclipse Java EE IDE for Web Developers.Version: Kepler Service Release 2 maven版本:Apache Maven 3.2.5 tomcat7版本:Apache Tomcat/7.0.54 建立web工程,在pox.xml中进行配置 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://