0

我编写了一些代码来使用 CXF 创建和运行 Web 服务客户端。我使用 JaxWsClientFactoryBean (不确定它是否是最佳解决方案)从 .wsdl 文件创建客户端。这里的目标是以编程方式避免使用 Spring 等。只需使用 Java 和 CXF 编写纯代码。

JaxWsClientFactoryBean cfb = new JaxWsClientFactoryBean();
cfb.setAddress(getServiceProperty(intClass, PROPERTY_KEY_URL_SUFFIX));
cfb.setServiceClass(intClass);
cfb.setOutInterceptors(getOutInterceptors(intClass));
cfb.setServiceName(SERVICE_NAME);
cfb.setWsdlURL("classpath:wsdl/" + intClass.getSimpleName() + ".wsdl");
cfb.setEndpointName(ENDPOINT_NAME);
Client client = cfb.create();
ClientProxy cp = new ClientProxy(client);
I intService = (I) 
   Proxy.newProxyInstance(intClass.getClassLoader(), new Class[] { intClass }, cp);

我真的不确定这是否正确完成,但是当我在本地运行此代码以及在 Tomcat 上部署它时它可以工作。

不幸的是,我需要在 Weblogic 上运行此代码,这会导致奇怪的异常:

Caused by: javax.wsdl.WSDLException: WSDLException: faultCode=PARSER_ERROR: org.w3c.dom.DOMException: HIERARCHY_REQUEST_ERR: An attempt was
made to insert a node where it is not permitted.
        at org.apache.cxf.wsdl11.WSDLManagerImpl.loadDefinition(WSDLManagerImpl.java:235)
        at org.apache.cxf.wsdl11.WSDLManagerImpl.getDefinition(WSDLManagerImpl.java:186)
        at org.apache.cxf.wsdl11.WSDLServiceFactory.<init>(WSDLServiceFactory.java:92)
        ... 26 more
Caused by: org.w3c.dom.DOMException: HIERARCHY_REQUEST_ERR: An attempt was made to insert a node where it is not permitted.
        at com.sun.org.apache.xerces.internal.dom.ParentNode.internalInsertBefore(ParentNode.java:356)
        at com.sun.org.apache.xerces.internal.dom.ParentNode.insertBefore(ParentNode.java:284)
        at com.sun.org.apache.xerces.internal.dom.CoreDocumentImpl.insertBefore(CoreDocumentImpl.java:399)
        at com.sun.org.apache.xerces.internal.dom.NodeImpl.appendChild(NodeImpl.java:235)
        at org.apache.cxf.staxutils.StaxUtils.readDocElements(StaxUtils.java:1019)
        at org.apache.cxf.staxutils.StaxUtils.readDocElements(StaxUtils.java:939)
        at org.apache.cxf.staxutils.StaxUtils.read(StaxUtils.java:866)
        at org.apache.cxf.wsdl11.WSDLManagerImpl.loadDefinition(WSDLManagerImpl.java:226)
        ... 28 more

这发生在应用程序部署期间。看起来 .wsdl 文件有问题,但是等等……它在 Tomcat 上运行!

我认为 Weblogic 中的 com.sun.org.apache.xerces.* 类实现与它的 JRockit VM 和标准 JVM 可能存在一些差异,但我不知道如何解决它。

我花了很多时间尝试不同的客户端创建方式。他们中的大多数在本地和 Tomcat 中工作,但在 WebLogic 上没有。

任何提示下一步该尝试什么?我有点厌倦这个话题:D

4

1 回答 1

3

我同意您的怀疑,即问题与使用的 Xerces 版本有关。堆栈跟踪显示在您的案例中使用了 Xerces 的 Sun 实现,它是 Apache Xerces 的衍生产品。

请查看与 WebLogic 相关的Apache CFX 应用程序服务器配置指南说明。

WebLogic 类加载

在 WebLogic Server 中,系统类路径中存在的任何 .jar 文件都由 WebLogic Server 系统类加载器加载。在服务器实例中运行的所有应用程序都加载到应用程序类加载器中,这些类加载器是系统类加载器的子级。在系统类加载器的这个实现中,应用程序不能使用系统类加载器中已经存在的不同版本的第三方 jar。每个子类加载器都向父类(系统类加载器)询问特定类,并且无法加载父类看到的类。

例如,如果一个名为 com.foo.Baz 的类同时存在于 $CLASSPATH 和应用程序 EAR 中,则加载来自 $CLASSPATH 的类而不是来自 EAR 的类。由于 weblogic.jar 在 $CLASSPATH 中,应用程序不能覆盖任何 WebLogic Server 类。

为了使用 Xerces 的替代版本,您必须创建一个 FilteringClassLoader。

FilteringClassLoader 的使用

FilteringClassLoader为您提供了一种机制来配置部署描述符,以明确指定应始终从应用程序加载某些包,而不是由系统类加载器加载。这允许您使用应用程序的替代版本,例如 Xerces 和 Ant。

FilteringClassLoader 位于应用程序类加载器和系统之间。它是系统类加载器的子类和应用程序类加载器的父类。FilteringClassLoader 拦截 loadClass(String className) 方法并将 className 与 weblogic-application.xml 文件中指定的包列表进行比较。

总之,检查Apache CFX 应用程序服务器配置指南中包含的步骤,并注意明确指定org.apache.xerces.*包是从应用程序加载的,而不是从系统类加载器加载的。

例如,META-INF 中的 weblogic-application.xml 文件应如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<weblogic-application xmlns="http://www.bea.com/ns/weblogic/90">
    <application-param>
        <param-name>webapp.encoding.default</param-name>
        <param-value>UTF-8</param-value>
    </application-param>
    <prefer-application-packages>
        <package-name>javax.jws.*</package-name>
        <package-name>org.apache.xerces.*</package-name>
    </prefer-application-packages>
</weblogic-application>

我希望这有帮助。

于 2013-01-27T17:35:58.203 回答