问题描述
作为this question的后续,我仍然对如何正确使用CXF-RS有点困惑组件.
As a follow-up to this question, I'm still a bit confused about how to properly use the CXF-RS component.
当我可以使用 <jaxrs:server> 标签非常好.
I'm confused why we need the <cxf:rsServer> tag for specifying CXF-RS endpoints (or is there even such a concept?), when I can use the <jaxrs:server> tag perfectly fine.
这是我对 Camel 和 CXF 的配置 XML:
Here's my configuration XML for both Camel and CXF:
<beans xmlns="http://www.51sjk.com/Upload/Articles/1/0/336/336738_20221115094851810.jpg" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.51sjk.com/Upload/Articles/1/0/336/336738_20221115094852574.jpg" xmlns:jaxrs="http://www.51sjk.com/Upload/Articles/1/0/336/336738_20221115094904653.jpg" xmlns:camel="http://www.51sjk.com/Upload/Articles/1/0/336/336738_20221115094905340.jpg" xsi:schemaLocation="http://www.51sjk.com/Upload/Articles/1/0/336/336738_20221115094851810.jpg http://www.51sjk.com/Upload/Articles/1/0/336/336738_20221115094851810.jpg/spring-beans.xsd http://www.51sjk.com/Upload/Articles/1/0/336/336738_20221115094852574.jpg http://www.51sjk.com/Upload/Articles/1/0/336/336738_20221115094852574.jpg/spring-context.xsd http://www.51sjk.com/Upload/Articles/1/0/336/336738_20221115094853247.jpg http://www.51sjk.com/Upload/Articles/1/0/336/336738_20221115094903309.xsd http://www.51sjk.com/Upload/Articles/1/0/336/336738_20221115094903561.jpg http://www.51sjk.com/Upload/Articles/1/0/336/336738_20221115094904496.xsd http://www.51sjk.com/Upload/Articles/1/0/336/336738_20221115094904653.jpg http://www.51sjk.com/Upload/Articles/1/0/336/336738_20221115094905169.xsd http://www.51sjk.com/Upload/Articles/1/0/336/336738_20221115094905340.jpg http://www.51sjk.com/Upload/Articles/1/0/336/336738_20221115094905340.jpg/camel-spring.xsd"> <jaxrs:server id="userService" address="/users"> <jaxrs:serviceBeans> <bean class="com.example.UserServiceNoop" /> </jaxrs:serviceBeans> <jaxrs:providers> <bean class="org.codehaus.jackson.jaxrs.JacksonJaxbJsonProvider" /> </jaxrs:providers> </jaxrs:server> <bean id="user" class="org.apache.camel.component.direct.DirectComponent" /> <camel:camelContext id="someCamelContext"> <camel:route id="userServiceRoute"> <camel:from uri="cxfrs:bean:userService" /> <camel:routingSlip> <camel:simple>user:${header.operationName}</camel:simple> </camel:routingSlip> </camel:route> <camel:route id="userServiceRetrieveUser"> <from uri="user:retrieveUser" /> <!-- Assume this is going to a useful Processor --> </camel:route> </camel:camelContext> </beans>
UserService.java:
UserService.java:
package com.example; /* a bunch of imports... */ public interface UserService { @GET @Path(value="/{user.id}") @Produces({MediaType.APPLICATION_JSON}) public User retrieveUser( @PathParam("user.id") Integer id ); }
UserServiceNoop.java
UserServiceNoop.java
package com.example; /* a bunch of imports ... */ public class UserServiceNoop implements UserService { @Override public User retrieveUser(Integer id) { throw new RuntimeException(); } }
在这个例子中,我没有使用任何 <cxf:rsServer> 标签,但它工作正常.我知道它通过 CXF-RS 组件,因为当我运行应用程序时,它不会抛出任何 RuntimeExceptions,这是使用 CXF-RS 时的预期行为(服务中的方法实现类不会被调用).
In this example, I'm not using any <cxf:rsServer> tag, yet it works fine. I know it goes through the CXF-RS component, because when I run the application, it doesn't throw any RuntimeExceptions, which is the expected behavior when using CXF-RS (the method implementation in the service class will not be called).
不使用这个标签是不是我错过了什么?
Am I missing something by not using this tag?
推荐答案
正如另一个答案所说, cxf:rsServer 主要用于由 Camel 路由处理,如 jaxrs:server 请求的处理由经典控制器完成.
As the other answer says, the cxf:rsServer is mainly used to be processed by a Camel route as in the jaxrs:server the processing of the request is done by a classic controller.
例如:
- 经典 JAXRS 服务器:
您将声明一个经典的 Bean Rest(控制器)并在其中注入一个服务.
You will declare a classic Bean Rest (Controller) and inject a Service inside.
XML 配置示例(摘录):
<jaxrs:server id="deviceServiceSvcV1" address="/device/v1"> <jaxrs:serviceBeans> <ref component-id="deviceServiceRest" /> </jaxrs:serviceBeans> <!-- and other providers, interceptors, etc... here --> </jaxrs:server> <!-- Service bean --> <bean id="deviceServiceRest" class="org.mycomp.device.rest.v1.ws.api.DeviceServiceRest"> <property name="deviceService" ref="deviceService" /> </bean>
Controller 类将以经典方式处理请求/响应(例如调用注入服务).
The Controller class will process the request / response in a classic way (e.g. calling an injected service).
- cxf:rsServer 的骆驼路线
- Camel route with cxf:rsServer
XML 配置示例(摘录):
<cxf:rsServer id="rsServer" address="/device/v1" serviceClass="org.mycomp.device.rest.v1.ws.api.DeviceServiceRest"> <cxf:properties> <!-- whatever here --> </cxf:properties> <!-- and other interceptors, etc... here --> </cxf:rsServer>
在课堂上:
@Produces({ MediaType.APPLICATION_XML }) @Path("/") public class DeviceServiceRest { @GET public Response listDevicess( @QueryParam("model") String model, @QueryParam("sid") String sid, ) { return null; // never used } @GET @Path("{id}") public Response getDeviceById( @PathParam("id") String id, @QueryParam("model") String model, @QueryParam("sid") String sid ){ return null; // never used } }
REST 控制器有空方法(返回 null),但我认为最新的 camel-cxf 现在支持 Interface,它比返回 的方法更优雅空.现在,请求处理可以通过 Camel Route 来实现,如下所示:
The REST Controller has empty methods (returning null) but I think the latest camel-cxf supports now an Interface which is more elegant than having methods returning null. Now, the request processing can be implemented by a Camel Route like this:
from("cxfrs:bean:rsServer?synchronous=true") .routeId("cxf-device-rest-v1") .process( new CheckAuthenticationProcessor()) .choice() .when(header("operationName").isEqualTo("listDevice")) .setHeader("backenOperation").constant("list") .setHeader("backendResource").constant("device") .endChoice() .when(header("operationName").isEqualTo("getDeviceById")) .setHeader("backenOperation").constant("retrieve") .setHeader("backendResource").constant("device") .endChoice() .end() .bean("requestProcessor") .to(InOut, backendEndpoint) .process(checkResponseStatusCode()) .bean(new HttpResponseProcessor()) ;
您还可以从路由中根据需要控制请求/响应处理.
And you can also control the request / response processing as you want from the route.
这是两种不同的实现 REST API(服务器端)的方式,但在我看来这有点老派,因为像 spring-boot 这样的现代框架不需要这些.
These are two different kind of implementing a REST API (server side) but in my opinion this is a bit old school as modern framework like spring-boot does not need any of these.
我发现第二种方法有点矫枉过正,因为我喜欢 Camel 用于集成目的,但将它用于 REST API 可能需要讨论.我可以看到的一个用例是用于异步处理的 HTTP REST Web 服务,响应 202 Accepted 的服务和 Camel Route 在异步模式下集成请求,特别是当可以轻松使用特定的 Camel 组件而不是复杂的组件时类(或任何需要 EIP 模式).
I found the second way a bit too much overkill as I like Camel for integration purpose but using it for a REST API could be subject to discussion. One use-case I can see is a HTTP REST Web-Service for asynchronous processing, the service responding 202 Accepted and the Camel Route making an integration of the request in asynchronous mode especially when a specific Camel Component can be easily used instead of a complex class (or any need of the EIP patterns).