29.4. 使用合同解析器

概述

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

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

实施合同解析器

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

例 29.3. ServiceContractResolver 接口

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

用于解析 WSDL 合同位置的逻辑特定于应用程序。您可以添加从 UDDI 注册表、数据库、文件系统中自定义位置或者您选择的任何其他机制解析合同位置的逻辑。

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

在 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 的 register()注册您的合同解析器。

例 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 配置合同解析器” 显示添加由 org.apache.cxf.demos.myContractResolver 类实施的配置解析器的 bean。

例 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 registry 注册了已解析 WSDL 位置的合同解析器,则 registry 可能会使用两个解析器查找服务的 WSDL 合同。注册表首先尝试使用共享文件系统合同解析器查找合同。如果该合同解析器失败,则 registry 会尝试使用 UDDI 合同解析器查找它。