46.6. 资源选择方法
概述
给定 URI 可以映射到一个或多个资源方法。例如,URI customerservice/12/ma 可以匹配 templates @Path ("customerservice/{id}")
或 @Path ("customerservice/{id}/{state}/{state}")
。JAX-RS 指定与请求匹配的资源方法的详细算法。该算法将规范化 URI、HTTP 动词和请求的介质类型与资源类上的注释进行比较。
基本选择算法
JAX-RS 选择算法分为三个阶段:
确定根资源类。
请求 URI 与以
@Path
注释分隔的所有类匹配。确定了@Path
注释与请求 URI 匹配的类。如果资源类的
@Path
注释的值与整个请求 URI 匹配,则类的方法将用作第三个阶段的输入。确定对象将处理请求。
如果请求 URI 大于所选类的
@Path
注释的值,则使用资源方法的@Path
注释的值来查找可处理请求的子资源。如果一个或多个子资源方法与请求 URI 匹配,则这些方法用作第三个阶段的输入。
如果请求 URI 的唯一匹配是子资源定位器,则由子资源定位器所创建的对象的资源方法与请求 URI 匹配。这个阶段会被重复,直到子资源方法与请求 URI 匹配。
选择处理请求的资源方法。
HTTP 动词注解与请求的 HTTP 动词匹配的资源方法。此外,所选的资源方法必须接受请求实体正文的媒体类型,并且能够生成符合请求中指定的介质类型的响应。
从多个资源类中选择
选择算法的前两个阶段决定了将处理请求的资源。在某些情况下,该资源由资源类实施。在其他情况下,它由使用同一 URI 模板的一个或多个子资源来实施。当有多个与请求 URI 匹配的资源时,资源类优先于子资源。
如果在资源类和子资源排序后,如果多个资源仍然与请求 URI 匹配,则会使用以下条件来选择单个资源:
优先选择其 URI 模板中带有最多字面字符的资源。
字面上的字符是不是模板变量一部分的字符。例如,/widgets/{id}/{color} 具有十个字面字符,/widgets/1/{color} 具有 eleven literal 字符。因此,请求 URI /widgets/1/red 将与 /widgets/1/{color} 作为其 URI 模板的资源匹配。
注意尾部斜杠()
计数
为一个字面字符。因此,/joefred/ 将比 /joefred 优先选择。首选使用 URI 模板中的大部分变量的资源。
请求 URI /widgets/30/green 可以匹配 /widgets/{id}/{color} 和 /widgets/{amount}/。但是,带有 URI 模板 /widgets/{id}/{color} 的资源会被选择,因为它有两个变量。
使用包含正则表达式的大部分变量选择该资源。
请求 URI /widgets/30/green 可以匹配 /widgets/{number}/{color} 和 /widgets/{idgets/{id:.}/{color}*。但是,带有 URI 模板 */widgets/{id:.}/{color} 的资源将被选择,因为它有一个包含正则表达式的变量。
从多个资源方法中选择
在很多情况下,选择与请求 URI 匹配的资源会导致单个资源方法处理请求。该方法通过与请求中指定的 HTTP 动词和资源方法的 HTTP 动词进行匹配来确定。除了具有适当的 HTTP 动词注解外,所选的方法还必须能够处理请求中包含的请求实体,并且能够生成正确的请求元数据中指定的响应类型。
资源方法可以处理的请求实体的类型通过 @Consumes
注释来指定。可以通过 @Produces
注释来指定资源方法生成的响应类型。
当选择资源会产生多个可以处理以下条件的方法时,会使用以下条件来选择处理请求的资源方法:
- 资源方法优先于子资源。
- 对于子资源定位器,首选子资源方法。
优先使用
@Consumes
注释和@Produces
注释中最具体值的方法。例如,具有注释
@Consumes ("text/xml")
的方法优先于具有注释@Consumes ("text/*")
的方法。这两种方法都优先于没有@Consumes
注释或注释@Consumes ("\*/*")
的方法。首选方法最接近请求正文实体的内容类型。
注意请求正文实体的内容类型在 HTTP
Content-Type
属性中指定。首选最符合内容类型的方法作为回答。
注意作为响应接受的内容类型在 HTTP
Accept
属性中指定。
自定义选择过程
在某些情况下,开发人员已报告了选择多个资源类的方式受到限制性。例如,如果给定资源类匹配,并且此类没有匹配资源方法,则算法将停止执行。它永远不会检查剩余的匹配资源类。
Apache CXF 提供 org.apache.cxf.jaxrs.ext.ResourceComparator 接口,可用于自定义运行时如何处理多个匹配资源类。ResourceComparator 接口(如 例 46.9 “用于自定义资源选择的接口” 所示)需要实施的方法。个比较了两个资源类,另一个资源则比较了两个资源方法。
例 46.9. 用于自定义资源选择的接口
package org.apache.cxf.jaxrs.ext; import org.apache.cxf.jaxrs.model.ClassResourceInfo; import org.apache.cxf.jaxrs.model.OperationResourceInfo; import org.apache.cxf.message.Message; public interface ResourceComparator { int compare(ClassResourceInfo cri1, ClassResourceInfo cri2, Message message); int compare(OperationResourceInfo oper1, OperationResourceInfo oper2, Message message); }
自定义实现在两个资源间进行选择,如下所示:
-
如果第一个参数
比第二个参数更好匹配,则返回 1 -
如果第二个参数比第一个参数更匹配,则返回
-1
如果返回 0,
则运行时将继续执行默认选择算法
您可以通过在服务的 jaxrs:server
元素中添加 resourceComparator
子来注册自定义资源Comparator 实现。