29.4. 使用合同解析器

概述

在运行时解析 WSDL 文档位置的最涉及的机制是实施您自己的自定义合同解析器。这要求您提供 Apache CXF 特定 ServiceContractResolver 接口的实现。您还需要将自定义解析器注册到总线。

正确注册后,将使用自定义合同解析器来解决任何所需的 WSDL 和架构文档的位置。

实施合同解析器

合同解析器是 org.apache.cxf.endpoint.ServiceContractResolver 接口的实现。如 例 29.3 “ServiceContractResolver Interface” 所示,这个接口有一个方法 getContractLocation (),需要实现它。getContractLocation () 采用服务的 QName,并返回服务的 WSDL 合同的 URI。

例 29.3. ServiceContractResolver Interface

public interface ServiceContractResolver
{
   URI getContractLocation(QName qname);
}

用于解析 WSDL 合同位置的逻辑特定于应用。您可以添加可解析来自 UDDI registry、数据库、文件系统上的自定义位置或您选择的任何其他机制的逻辑。

以编程方式注册合同解析器

在 Apache CXF 运行时将使用您的合同解析器前,您必须将其注册到合同解析器 registry。合同解析器 registry 实施 org.apache.cxf.endpoint.ServiceContractResolverRegistry 接口。但是,您不需要实施自己的 registry。Apache CXF 在 org.apache.cxf.endpoint.ServiceContractResolverRegistryImpl 类中提供默认实现。

要将合同解析器注册到默认 registry,请执行以下操作:

  1. 获取对默认总线对象的引用。
  2. 使用总线的 getExtension () 方法从总线获取服务合同 registry。
  3. 创建合同解析器的实例。
  4. 使用 registry 的 register () 方法将合同解析器注册到 registry。

例 29.4 “注册合同解析器” 显示将合同解析器注册到默认 registry 的代码。

例 29.4. 注册合同解析器

BusFactory bf=BusFactory.newInstance();
Bus bus=bf.createBus();

ServiceContractResolverRegistry registry = bus.getExtension(ServiceContractResolverRegistry);

JarServiceContractResolver resolver = new JarServiceContractResolver();

registry.register(resolver);

例 29.4 “注册合同解析器” 中的代码执行以下操作:

获取总线实例。

获取总线的合同解析器 registry。

创建合同解析器实例。

将合同解析器注册到 registry。

使用配置注册合同解析器

您还可以实施合同解析器,以便通过配置将其添加到客户端。合同解析器采用这样一种方式,即当运行时读取配置并实例化解析器(解析器)时,解析器会自行注册。由于运行时处理初始化,因此您可以在运行时决定客户端是否需要使用合同解析器。

要实现合同解析器,以便可以通过配置将其添加到客户端中:

  1. 在您的合同解析器实施中添加 init () 方法。
  2. 在您的 init () 方法中添加逻辑,以将合同解析器注册到合同解析器 registry,如 例 29.4 “注册合同解析器” 所示。
  3. 使用 @PostConstruct 注释拒绝 init () 方法。

例 29.5 “可使用配置注册的服务合同解析器” 显示了可以使用 配置添加到客户端中的合同解析器实施。

例 29.5. 可使用配置注册的服务合同解析器

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.xml.namespace.QName;

import org.apache.cxf.Bus;
import org.apache.cxf.BusFactory;

public class UddiResolver implements ServiceContractResolver
{
  private Bus bus;
  ...

  @PostConstruct
  public void init()
  {
    BusFactory bf=BusFactory.newInstance();
    Bus bus=bf.createBus();
    if (null != bus)
    {
      ServiceContractResolverRegistry resolverRegistry = bus.getExtension(ServiceContractResolverRegistry.class);
      if (resolverRegistry != null)
      {
        resolverRegistry.register(this);
      }
    }
  }

  public URI getContractLocation(QName serviceName)
  {
    ...
  }
}

要将合同解析器注册到客户端,您需要向客户端的配置中添加 bean 元素。bean 元素的 class 属性是实施合同解析器的类的名称。

例 29.6 “Bean 配置合同解析器” 显示一个 bean,用于添加由 org.apache.cxf.demos.myContractResolver 类实现的配置解析器。

例 29.6. Bean 配置合同解析器

<beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
  ...
  <bean id="myResolver" class="org.apache.cxf.demos.myContractResolver" />
  ...
</beans>

合同解析顺序

创建新代理时,运行时使用合同注册表解析器来查找远程服务的 WSDL 合同。合同解析器 registry 按照注册解析器的顺序调用每个合同解析器的 getContractLocation () 方法。它返回从其中一个注册的合同解析器返回的第一个 URI。

如果您注册了一个在已知已知共享文件系统上解析 WSDL 合同的合同解析器,则它是唯一使用的合同解析器。但是,如果您随后注册了一个使用 UDDI 注册表解析 WSDL 位置的合同解析器,registry 就可以使用两个解析器来定位服务的 WSDL 合同。该注册表首先会尝试使用共享文件系统合同解析器查找合同。如果该合同解析器失败,registry 将尝试使用 UDDI 合同解析器查找它。