第 18 章 配置 JAX-RS 端点

摘要

本章论述了如何在 Blueprint XML 和 Spring XML 中实例化和配置 JAX-RS 服务器端点,以及如何在 XML 中实例化和配置 JAX-RS 客户端端点(客户端代理 Bean)

18.1. 配置 JAX-RS 服务器端点

18.1.1. 定义 JAX-RS 服务器端点

基本服务器端点定义

要在 XML 中定义 JAX-RS 服务器端点,您需要至少指定以下内容:

  1. jaxrs:server 元素,用于定义 XML 中的端点。请注意,jaxrs: 命名空间前缀分别映射到 Blueprint 和 Spring 中的不同命名空间。
  2. 使用 jaxrs:server 元素的地址属性的 JAX-RS 服务的基本 URL。请注意,有两种不同的方法来指定地址 URL,这会影响端点的部署方式:

    • 作为相对 URL- 例如: /customers。在本例中,端点被部署到默认的 HTTP 容器中,通过将 CXF servlet 基本 URL 与指定的相对 URL 相结合,端点的基本 URL 会被隐式获得。

      例如,如果您将 JAX-RS 端点部署到 Fuse 容器,则指定的 /customers URL 将解析为 URL http://Hostname:8181/cxf/customers (假设容器使用默认的 8181 端口)。

    • 作为绝对 URL 10.10.10.2-sHistoryLimit,例如 http://0.0.0.0:8200/cxf/customers。在本例中,为 JAX-RS 端点打开一个新的 HTTP 侦听器端口(如果尚未打开)。例如,在 Fuse 上下文中,会隐式创建新的 Undertow 容器以托管 JAX-RS 端点。特殊的 IP 地址 0.0.0.0 充当通配符,匹配分配给当前主机的任何主机名(对于多设备主机机器很有用)。
  3. 一个或多个 JAX-RS 根资源类,提供 JAX-RS 服务的实施。指定资源类的最简单方法是在 jaxrs:serviceBeans 元素内列出它们。

蓝图示例

以下 Blueprint XML 示例演示了如何定义 JAX-RS 端点,该端点指定相对地址 /customers (因此将其部署到默认 HTTP 容器)并由 service.CustomerService 资源类实施:

<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:jaxrs="http://cxf.apache.org/blueprint/jaxrs"
    xmlns:cxf="http://cxf.apache.org/blueprint/core"
    xsi:schemaLocation="
http://www.osgi.org/xmlns/blueprint/v1.0.0 https://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd
http://cxf.apache.org/blueprint/jaxrs http://cxf.apache.org/schemas/blueprint/jaxrs.xsd
http://cxf.apache.org/blueprint/core http://cxf.apache.org/schemas/blueprint/core.xsd
">

    <cxf:bus>
        <cxf:features>
            <cxf:logging/>
        </cxf:features>
    </cxf:bus>

     <jaxrs:server id="customerService" address="/customers">
        <jaxrs:serviceBeans>
           <ref component-id="serviceBean" />
        </jaxrs:serviceBeans>
     </jaxrs:server>

     <bean id="serviceBean" class="service.CustomerService"/>
</blueprint>

蓝图 XML 命名空间

要在 Blueprint 中定义 JAX-RS 端点,通常需要以下 XML 命名空间:

Spring 示例

以下 Spring XML 示例演示了如何定义 JAX-RS 端点,用于指定相对地址 /customers (因此将其部署到默认 HTTP 容器)并由 服务实施。CustomerService 资源类:

<beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:jaxrs="http://cxf.apache.org/jaxrs"
      xsi:schemaLocation="
         http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
         http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd">

     <jaxrs:server id="customerService" address="/customers">
        <jaxrs:serviceBeans>
           <ref bean="serviceBean"/>
        </jaxrs:serviceBeans>
     </jaxrs:server>

     <bean id="serviceBean" class="service.CustomerService"/>
</beans>

Spring XML 命名空间

要在 Spring 中定义 JAX-RS 端点,通常需要以下 XML 命名空间:

Spring XML 中的自动发现

(仅) 明确指定 JAX-RS 根资源类,Spring XML 可让您配置自动发现,以便搜索特定 Java 软件包以获取资源类(由 @Path标注的类),并且所有发现的资源类都自动附加到端点。在这种情况下,您需要在 jaxrs:server 元素中仅指定 address 属性和 basePackages 属性。

例如,若要定义使用 a.b.c Java 软件包下的所有 JAX-RS 资源类的 JAX-RS 端点,您可以在 Spring XML 中定义端点,如下所示:

<jaxrs:server address="/customers" basePackages="a.b.c"/>

自动发现机制还会发现并安装到端点,在其在指定的 Java 软件包下找到的任何 JAX-RS 提供程序类。

Spring XML 中的生命周期管理

(仅限 Spring XML) 通过设置 bean 元素上的 scope 属性来控制 Bean 的生命周期。Spring 支持以下范围值:

单例
(默认) 创建一个单个 bean 实例,该实例在 Spring 容器的整个生命周期中使用。
prototype
每次将 bean 注入到另一个 bean 或 bean 获取 bean 时,或通过调用 bean registry 上的 getBean() 来新建一个 bean 实例。
Request(请求)
(仅适用于 Web 感知型容器) 为 Bean 上调用的每个请求创建一个新的 bean 实例。
session
(只在一个 Web 感知容器中可用) 为单个 HTTP 会话生命周期创建一个新 Bean。
globalSession
(只在一个 Web 感知容器中可用) 为在 portlet 之间共享的单个 HTTP 会话的生命周期创建一个新 Bean。

如需有关 Spring 范围的更多详细信息,请参阅有关 Bean 范围的 Spring 框架文档。

请注意,如果您通过 jaxrs:serviceBeans 元素指定 JAX-RS 资源 Bean,Spring 范围 无法正常工作。如果您在此例中指定 resource Bean 上的 scope 属性,则 scope 属性将有效忽略。

要让 bean 范围在 JAX-RS 服务器端点内正常工作,您需要一个由服务工厂提供的间接级别。配置 bean 范围的最简单方法是使用 jaxrs:server 元素上的 beanNames 属性来指定 resourceanNames 属性,如下所示:

<beans ... >
  <jaxrs:server id="customerService" address="/service1"
    beanNames="customerBean1 customerBean2"/>

  <bean id="customerBean1" class="demo.jaxrs.server.CustomerRootResource1" scope="prototype"/>
  <bean id="customerBean2" class="demo.jaxrs.server.CustomerRootResource2"  scope="prototype"/>
</beans>

上一示例配置两个资源 Bean,即 customerBean1customerBean2beanNames 属性指定为空格分隔的资源 bean ID 列表。

为了获得灵活性,您可以 显式 定义服务工厂对象的选项,当您使用 jaxrs:serviceFactories 元素配置 JAX-RS 服务器端点时。这种更详细的方法有优势,您可以将默认服务工厂实施替换为您的自定义实施,从而让您最终掌控 bean 生命周期。以下示例演示了如何使用此方法配置两个资源 Bean、customerBean1customerBean2

<beans ... >
  <jaxrs:server id="customerService" address="/service1">
    <jaxrs:serviceFactories>
      <ref bean="sfactory1" />
      <ref bean="sfactory2" />
    </jaxrs:serviceFactories>
  </jaxrs:server>

  <bean id="sfactory1" class="org.apache.cxf.jaxrs.spring.SpringResourceFactory">
     <property name="beanId" value="customerBean1"/>
  </bean>
  <bean id="sfactory2" class="org.apache.cxf.jaxrs.spring.SpringResourceFactory">
     <property name="beanId" value="customerBean2"/>
  </bean>

  <bean id="customerBean1" class="demo.jaxrs.server.CustomerRootResource1" scope="prototype"/>
  <bean id="customerBean2" class="demo.jaxrs.server.CustomerRootResource2"  scope="prototype"/>
</beans>
注意

如果您指定了非单例生命周期,则通常最好实施和注册 org.apache.cxf.service.Invoker bean(其中,可以通过引用来自 jaxrs:server/jaxrs:invoker 元素来注册实例)。

附加 WADL 文档

您可以使用 jaxrs:server 元素上的 docLocation 属性,将 WADL 文档与 JAX-RS 服务器端点关联。例如:

<jaxrs:server address="/rest" docLocation="wadl/bookStore.wadl">
   <jaxrs:serviceBeans>
      <bean class="org.bar.generated.BookStore"/>
   </jaxrs:serviceBeans>
</jaxrs:server>

模式验证

如果您有一些外部 XML 模式,用于描述 JAX-B 格式的消息内容,您可以通过 jaxrs:schemaLocations 将这些外部模式与 JAX-RS 服务器端点关联。

例如,如果您已将服务器端点与 WADL 文档相关联,并且您希望在传入消息上启用 schema 验证,您可以按如下方式指定相关的 XML 架构文件:

<jaxrs:server address="/rest"
              docLocation="wadl/bookStore.wadl">
   <jaxrs:serviceBeans>
     <bean class="org.bar.generated.BookStore"/>
   </jaxrs:serviceBeans>
   <jaxrs:schemaLocations>
     <jaxrs:schemaLocation>classpath:/schemas/a.xsd</jaxrs:schemaLocation>
     <jaxrs:schemaLocation>classpath:/schemas/b.xsd</jaxrs:schemaLocation>
   </jaxrs:schemaLocations>
</jaxrs:server>

或者,如果您要将所有模式文件( *.xsd )包含在给定目录中,您可以只指定目录名称,如下所示:

<jaxrs:server address="/rest"
              docLocation="wadl/bookStore.wadl">
   <jaxrs:serviceBeans>
     <bean class="org.bar.generated.BookStore"/>
   </jaxrs:serviceBeans>
   <jaxrs:schemaLocations>
     <jaxrs:schemaLocation>classpath:/schemas/</jaxrs:schemaLocation>
   </jaxrs:schemaLocations>
</jaxrs:server>

以这种方式指定架构对于需要访问 JAX-B 模式的任何种类的功能通常有用。

指定数据绑定

您可以使用 jaxrs:dataBinding 元素指定在请求和回复消息中编码消息正文的数据绑定。例如,若要指定 JAX-B 数据的绑定,您可以配置 JAX-RS 端点,如下所示:

<jaxrs:server id="jaxbbook" address="/jaxb">
  <jaxrs:serviceBeans>
    <ref bean="serviceBean" />
  </jaxrs:serviceBeans>
  <jaxrs:dataBinding>
    <bean class="org.apache.cxf.jaxb.JAXBDataBinding"/>
  </jaxrs:dataBinding>
</jaxrs:server>>

或者指定 Aegis 数据的绑定,您可以按照如下所示配置 JAX-RS 端点:

<jaxrs:server id="aegisbook" address="/aegis">
  <jaxrs:serviceBeans>
    <ref bean="serviceBean" />
  </jaxrs:serviceBeans>
  <jaxrs:dataBinding>
    <bean class="org.apache.cxf.aegis.databinding.AegisDatabinding">
      <property name="aegisContext">
        <bean class="org.apache.cxf.aegis.AegisContext">
          <property name="writeXsiTypes" value="true"/>
        </bean>
      </property>
    </bean>
  </jaxrs:dataBinding>
</jaxrs:server>

使用 JMS 传输

可以将 JAX-RS 配置为将 JMS 消息库用作传输协议,而不使用 HTTP。由于 JMS 本身 不是 传输协议,因此实际的消息传递协议取决于您配置的特定 JMS 实施。

例如,以下 Spring XML 示例演示了如何配置 JAX-RS 服务器端点以使用 JMS 传输协议:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:jms="http://cxf.apache.org/transports/jms"
       xmlns:jaxrs="http://cxf.apache.org/jaxrs"
       xsi:schemaLocation="
http://cxf.apache.org/transports/jms http://cxf.apache.org/schemas/configuration/jms.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd">

    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"/>
    <bean id="ConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
        <property name="brokerURL" value="tcp://localhost:${testutil.ports.EmbeddedJMSBrokerLauncher}" />
    </bean>

    <jaxrs:server xmlns:s="http://books.com"
    	serviceName="s:BookService"
    	transportId= "http://cxf.apache.org/transports/jms"
    	address="jms:queue:test.jmstransport.text?replyToName=test.jmstransport.response">
        <jaxrs:serviceBeans>
            <bean class="org.apache.cxf.systest.jaxrs.JMSBookStore"/>
        </jaxrs:serviceBeans>
    </jaxrs:server>

</beans>

请注意,以下有关上例的几点:

  • JMS 实施- JMS 实施由 ConnectionFactory bean 提供,后者实例化 Apache ActiveMQ 连接工厂对象。在实例化连接工厂后,它会作为默认的 JMS 实现层自动安装。
  • JMS conduit 或 destination 对象-Apache CXF 隐式实例化 JMS conduit 对象(代表 JMS 消费者)或 JMS 目标对象(代表 JMS 提供程序)。这个对象必须由 QName 唯一标识,它通过 setttings xmlns:s="http://books.com" 定义(定义命名空间前缀)和 serviceName="s:BookService"( 定义 QName)。
  • 传输 ID- 要选择 JMS 传输,transportId 属性必须设置为 http://cxf.apache.org/transports/jms
  • JMS 地址- jaxrs:server/@address 属性使用标准化语法来指定要发送到的 JMS 队列或 JMS 主题。有关此语法的详情,请参考 https://tools.ietf.org/id/draft-merrick-jms-uri-06.txt

扩展映射和语言映射

可以配置 JAX-RS 服务器端点,使它自动将文件后缀(在 URL 中应用)映射到 MIME 内容类型标头,并将语言后缀映射到语言类型标头。例如,考虑以下形式的 HTTP 请求:

GET /resource.xml

您可以配置 JAX-RS 服务器端点,以自动映射 .xml 后缀,如下所示:

<jaxrs:server id="customerService" address="/">
  <jaxrs:serviceBeans>
    <bean class="org.apache.cxf.jaxrs.systests.CustomerService" />
  </jaxrs:serviceBeans>
  <jaxrs:extensionMappings>
    <entry key="json" value="application/json"/>
    <entry key="xml" value="application/xml"/>
  </jaxrs:extensionMappings>
</jaxrs:server>

当上述服务器端点收到 HTTP 请求时,它会自动创建类型为 application/xml 的新内容类型标头,并从资源 URL 剥离 .xml 后缀。

对于语言映射,请考虑以下格式的 HTTP 请求:

GET /resource.en

您可以配置 JAX-RS 服务器端点,以自动映射 .en 后缀,如下所示:

<jaxrs:server id="customerService" address="/">
  <jaxrs:serviceBeans>
    <bean class="org.apache.cxf.jaxrs.systests.CustomerService" />
  </jaxrs:serviceBeans>
  <jaxrs:languageMappings>
     <entry key="en" value="en-gb"/>
  </jaxrs:languageMappings>
</jaxrs:server>

当上述服务器端点收到 HTTP 请求时,它会自动创建一个新的接受语言标头,值为 en-gb,并从资源 URL 剥离 .en 后缀。

18.1.2. jaxrs:server 属性

属性

表 18.1 “JAX-RS 服务器端点属性” 描述 jaxrs:server 元素中可用的属性。

表 18.1. JAX-RS 服务器端点属性

属性描述

id

指定其他配置元素可用于引用端点的唯一标识符。

address

指定 HTTP 端点的地址。这个值将覆盖服务合同中指定的值。

basePackages

(仅限 Spring) 启用自动发现功能,方法是指定以逗号分隔的 Java 软件包列表,这些列表用于发现 JAX-RS 根资源类和/或 JAX-RS 提供程序类。

beanNames

指定 JAX-RS root 资源 Bean ID 的以空格分开的列表。在 Spring XML 上下文中,可以通过设置 root 资源 bean 元素上的 scope 属性来定义根资源 Bean 的生命周期。

bindingId

指定服务使用的消息绑定 ID。第 23 章 Apache CXF Binding ID 中提供了有效绑定 ID 列表。

总线

指定 Spring Bean 的 ID,配置用于管理服务端点的总线。这在将多个端点配置为使用一组通用的功能时,这很有用。

docLocation

指定外部 WADL 文档的位置。

modelRef

将模型 schema 指定为类路径资源(例如,classpath :/path/to/model.xml的 URL)。有关如何定义 JAX-RS 模型架构的详细信息,请参阅 第 18.3 节 “使用模型架构定义 REST 服务”

publish

指定是否应该自动发布该服务。如果设置为 false,则开发人员必须明确发布端点。

publishedEndpointUrl

指定 URL 基础地址,该地址将插入到自动生成的 WADL 接口的 wadl:resources/@base 属性中。

serviceAnnotation

(仅限 Spring) 指定 Spring 中自动发现的服务注解类名称。与 basePackages 属性结合使用时,此选项将限制自动发现类的集合,使其 仅包含 此注解类型所标注的类。猜!这是否正确?

serviceClass

指定 JAX-RS 根资源类的名称(实施 JAX-RS 服务)。在这种情况下,类由 Apache CXF 进行实例化,而不是由 Blueprint 或 Spring 进行实例化。如果要在 Blueprint 或 Spring 中实例化类,请使用 jaxrs:serviceBeans 子元素。

serviceName

指定在使用 JMS 传输的特殊情况下,为 JAX-RS 端点指定服务 QName(使用 ns:name)。详情请查看 “使用 JMS 传输”一节

staticSubresourceResolution

如果为 true,则禁用静态子资源的动态解析。默认为 false

transportId

用于选择非标准传输层(替换 HTTP)。特别是,您可以通过将此属性设置为 http://cxf.apache.org/transports/jms 来选择 JMS 传输。详情请查看 “使用 JMS 传输”一节

abstract

(仅限 Spring) 指定 bean 是否为抽象 bean。abstract Bean 充当拥塞 Bean 定义且没有实例化的父项。默认值为 false。将其设置为 true 指示 bean 工厂不会实例化 bean。

dependent-on

(Spring only) 指定端点在端点实例化之前要实例化的 Bean 列表,然后可以实例化该端点。

18.1.3. jaxrs:server Child Elements

子元素

表 18.2 “JAX-RS 服务器端点子元素” 描述 jaxrs:server 元素的子元素。

表 18.2. JAX-RS 服务器端点子元素

元素描述

jaxrs:executor

指定用于该服务的 Java 执行程序 (线程池实施)。这使用嵌入式 bean 定义进行指定。

jaxrs:features

指定 Beans 列表,用于配置 Apache CXF 的高级功能。您可以提供 bean 引用列表或嵌入式 Bean 列表。

jaxrs:binding

未使用.

jaxrs:dataBinding

指定实施端点使用的数据绑定的类。这使用嵌入式 bean 定义进行指定。如需了解更多详细信息,请参阅 “指定数据绑定”一节

jaxrs:inInterceptors

指定处理入站请求的拦截器列表。更多信息请参阅 第 VII 部分 “开发 Apache CXF Interceptors”

jaxrs:inFaultInterceptors

指定处理入站错误信息的拦截器列表。更多信息请参阅 第 VII 部分 “开发 Apache CXF Interceptors”

jaxrs:outInterceptors

指定处理出站回复的拦截器列表。更多信息请参阅 第 VII 部分 “开发 Apache CXF Interceptors”

jaxrs:outFaultInterceptors

指定处理出站错误信息的拦截器列表。更多信息请参阅 第 VII 部分 “开发 Apache CXF Interceptors”

jaxrs:invoker

指定服务使用的 org.apache.cxf.service.Invoker 接口的实施。[a]

jaxrs:serviceFactories

为您提供对与此端点关联的 JAX-RS 根资源的生命周期的最大控制程度。此元素的子项(必须是 org.apache.cxf.jaxrs.lifecycle.ResourceProvider 类型的实例)用于创建 JAX-RS 根资源实例。

jaxrs:properties

指定传递给端点的属性的 Spring 映射。这些属性可用于控制启用 MTOM 支持等功能。

jaxrs:serviceBeans

此元素的子项是(an 元素)的实例或引用(ref 元素)JAX-RS 根资源。请注意,如果 bean 元素中存在 scope 属性 (仅限 Spring), 则忽略。

jaxrs:modelBeans

由一个或多个 org.apache.cxf.jaxrs.model.UserResource Bean 组成,它们是资源模型的基本元素(与 jaxrs:resource 元素)的引用列表。详情请查看 第 18.3 节 “使用模型架构定义 REST 服务”

jaxrs:model

在此端点中直接定义资源模型(即,这个 jaxrs:model 元素可以包含一个或多个 jaxrs:resource 元素)。详情请查看 第 18.3 节 “使用模型架构定义 REST 服务”

jaxrs:providers

使您能够使用此端点注册一个或多个自定义 JAX-RS 提供程序。此元素的子项是(an 元素)的实例或引用(ref 元素)JAX-RS 提供程序。

jaxrs:extensionMappings

当 REST 调用的 URL 以文件扩展结尾时,您可以使用此元素将其与特定内容类型关联。例如,.xml 文件扩展名可以与 application/xml 内容类型关联。详情请查看 “扩展映射和语言映射”一节

jaxrs:languageMappings

当 REST 调用的 URL 以语言后缀结尾时,您可以使用此元素将这个元素映射到特定的语言。例如,.en 语言后缀可以与 en-GB 语言关联。详情请查看 “扩展映射和语言映射”一节

jaxrs:schemaLocations

指定验证 XML 消息内容的一个或多个 XML 模式。此元素可以包含一个或多个 jaxrs:schemaLocation 元素,各自指定 XML 架构文件的位置(通常是 类路径 URL)。详情请查看 “模式验证”一节

jaxrs:resourceComparator

可让您注册自定义资源比较器,它实施用于匹配特定资源类或方法的传入 URL 路径的算法。

jaxrs:resourceClasses

如果要从类名称创建多个资源,则只使用 jaxrs:server/@serviceClass 属性(blueprint) 而不是使用 jaxrs:server/@serviceClass 属性。jaxrs:resourceClasses 的子项必须是将 name 属性设置为资源名称 的类 元素。在这种情况下,类由 Apache CXF 进行实例化,而不是由 Blueprint 或 Spring 进行实例化。

[a] Invoker 实施控制如何调用服务。例如,它控制每个请求是否由服务实施的新实例处理,或在调用中保留状态。