Почему мы используем ‹cxf:rsServer› вместо простого ‹jaxrs:server› при использовании компонента CXF-RS?

В ответ на этот вопрос я все еще немного не понимаю, как правильно использовать компонент CXF-RS.

Я не понимаю, зачем нам нужен тег <cxf:rsServer> для указания конечных точек CXF-RS (или вообще существует такая концепция?), когда я могу прекрасно использовать тег <jaxrs:server>.

Вот мой XML конфигурации для Camel и CXF:

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:jaxrs="http://cxf.apache.org/jaxrs"
    xmlns:camel="http://camel.apache.org/schema/spring"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd      
        http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd
        http://cxf.apache.org/transports/http/configuration http://cxf.apache.org/schemas/configuration/http-conf.xsd
        http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd
        http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/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:

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

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 (реализация метода в сервисном классе не будет вызываться).

Я что-то упускаю, не используя этот тег?


person Ivan Gozali    schedule 29.01.2014    source источник


Ответы (2)


Вы используете тег cxf:reserver, когда хотите использовать конечную точку CXF в качестве потребителя чего-либо. Скажем, например, в сложном маршруте Apache Camel или в интеграции Spring. используется, когда вы являетесь поставщиком конечных точек, обслуживающих запросы.

person ArunR    schedule 03.07.2014

Как говорится в другом ответе, cxf:rsServer в основном используется для обработки маршрутом Camel, так как в jaxrs:server обработка запроса выполняется классическим контроллером.

Например:

  1. Классический JAXRS-сервер:

Вы объявите классический Bean Rest (контроллер) и внедрите службу внутри.

Пример конфигурации 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 будет обрабатывать запрос/ответ классическим способом (например, вызов внедренной службы).

  1. Верблюжий маршрут с 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, который более элегантен, чем методы, возвращающие null. Теперь обработка запроса может быть реализована с помощью Camel Route следующим образом:

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())
;

И вы также можете управлять обработкой запроса/ответа, как хотите, из маршрута.

Это два разных вида реализации REST API (на стороне сервера), но, на мой взгляд, это немного старая школа, поскольку современная среда, такая как spring-boot, не нуждается ни в одном из них.

Я нашел второй способ слишком излишним, так как мне нравится Camel для целей интеграции, но его использование для REST API может быть предметом обсуждения. Один из вариантов использования, который я вижу, - это веб-служба HTTP REST для асинхронной обработки, служба, отвечающая 202 Accepted, и Camel Route, выполняющая интеграцию запроса в асинхронном режиме, особенно когда конкретный компонент Camel можно легко использовать вместо сложного класс (или любая потребность в шаблонах EIP).

person рüффп    schedule 27.11.2020