RESTEasy не будет отображать мой bean-компонент Spring с пользовательским Spring ContextLoader - PullRequest
6 голосов
/ 30 марта 2011
  • RESTEasy 2.0.1GA
  • Java 1.6
  • Spring 3.0.3

Я перепробовал все, что мог, и не могу сделать голову или хвосто том, что происходит.У меня есть приложение Spring MVC, однако мне бы хотелось, чтобы некоторые конечные точки RESTEasy были доступны вне приложения Spring MVC, но в том же контейнере, что в конечном итоге позволило бы подключаться к одним и тем же компонентам.

В качестве первого шага я просто пытаюсь настроить RESTEasy внутри контейнера, обслуживая запросы от bean-компонента, настроенного Spring.Я пробовал шаблон из инструкции и также пробовал ручную настройку, но безрезультатно.

Боб

@Resource
@Path("/")
public class NeighborComparison {

    private String foo;

    @GET @Path(value="customer") @Produces("text/plain")
    public String getNeighborComparison() {
        return "foo";
    }
}

web.xml

<context-param>
    <param-name>resteasy.servlet.mapping.prefix</param-name>
    <param-value>/api</param-value>
</context-param>

<listener>
    <listener-class>org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap</listener-class>
</listener>

<!-- NOT configuring SpringContextLoaderListener because I declare my own, so if I do, everything
     blows up, plus  all it actually does is sanity check configuration -->
<listener>
    <listener-class>com.example.MyCustomContextLoaderListener</listener-class>
</listener>

<servlet>
    <servlet-name>Resteasy</servlet-name>
    <servlet-class>org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher</servlet-class>
</servlet>

<servlet-mapping>
    <servlet-name>Resteasy</servlet-name>
    <url-pattern>/api/*</url-pattern>
</servlet-mapping>

applicationContext.xml

<bean id="resteasy.providerFactory" class="org.jboss.resteasy.spi.ResteasyProviderFactory"
      factory-method="getInstance">
</bean>

<bean id="resteasy.dispatcher" class="org.jboss.resteasy.core.SynchronousDispatcher">
    <constructor-arg ref="resteasy.providerFactory"/>
</bean>

<bean id="resteasy.spring.bean.processor" class="org.jboss.resteasy.plugins.spring.SpringBeanProcessor">
    <description>
        Add Resources and @Providers to the appropriate places
        in Resteasy's infrastructure
    </description>
    <constructor-arg ref="resteasy.dispatcher"/>
</bean>

<bean id="neighborComparison" class="opower.api.customer.neighbor_comparison.NeighborComparison">
</bean>

В соответствии с документацией все, что мне нужно сделать, это «вручную зарегистрировать RESTeasy BeanFactoryPostProcessor, выделив экземпляр org.jboss.resteasy.plugins.spring.SpringBeanProcessor».Я полагаю, что эта весенняя конфигурация делает это.

Jetty запускается, и контекст приложения вращается без проблем.Приложение работает нормально, однако, когда я

> curl -H"Accept: text/plain" localhost:8080/ei/api/customer

("ei" - это контекст приложения).Журнал показывает (это и только это):

2011-03-29 16:44:24,153 DEBUG [qtp-575315405-0] [EI] [] [asy.core.SynchronousDispatcher] PathInfo: /customer
2011-03-29 16:44:24,156 DEBUG [qtp-575315405-0] [EI] [] [asy.core.SynchronousDispatcher] Failed executing GET /customer
org.jboss.resteasy.spi.NotFoundException: Could not find resource for relative : /customer of full path: http://localhost:8080/ei/api/customer

Даже если бы я мог убедить RESTEasy показать мне сопоставления, кажется, что он просто не обнаруживает мой бин.

Если я сопоставляюэто явно через параметр контекста resteasy.resources, оно работает, хотя, очевидно, не имеет доступа к автоматически подключаемым компонентам Spring.

Что-нибудь еще, что я могу попробовать?У меня есть журнал отладки на всей базе кода RESTEasy, и я не получаю никаких сообщений.Я также подтвердил, что Spring, по сути, создает мой бин, так что просто RESTEasy его не находит.

1 Ответ

8 голосов
/ 30 марта 2011

Ваш класс ресурсов должен быть аннотирован с помощью @Path аннотации, чтобы RESTeasy мог определить его во время начальной загрузки:

@Path("/customer")
@Resource
public class NeighborComparison {

    @GET @Path("/{customerId}") @Produces("text/plain")
    public String getNeighborComparison(@PathParam("customerId") long customerId) {
        return "foo";
    }
}

Обратите внимание на аннотацию @Path("/{customerId}}, без которой ваш параметр @PathParam не был бы отображен правильно, что привело бы к довольно подробному исключению (и сопровождающему ответу 500 на стороне клиента). Если, конечно, RESTeasy забирает услугу.

Кроме того, если вы не используете RESTeasy SpringContextLoader, вы должны убедиться, что ваш экземпляр SpringBeanProcessor зарегистрирован в ApplicationContext. RESTeasy делегирует его, зарегистрировав ApplicationListener в SpringContextLoader:

  ApplicationListener listener = new ApplicationListener() {
     public void onApplicationEvent(ApplicationEvent event) {
        if (event instanceof ContextRefreshedEvent) {
           ContextRefreshedEvent cre = (ContextRefreshedEvent) event;
           ConfigurableListableBeanFactory autowireCapableBeanFactory = (ConfigurableListableBeanFactory) cre
                 .getApplicationContext().getAutowireCapableBeanFactory();
           new SpringBeanProcessor(dispatcher, registry, providerFactory)
                 .postProcessBeanFactory(autowireCapableBeanFactory);
        }
     }
  };
  configurableWebApplicationContext.addApplicationListener(listener);

Если используется пользовательский загрузчик контекста и , а не предоставляемый RESTEasy, этот код должен появиться где-то в вашем загрузчике контекста, чтобы все было подключено. Немного запутанный, да. Это SpringBeanProcessor, который проходит через все bean-компоненты Spring и регистрирует с помощью RESTeasy те, которые имеют аннотацию @Path где-то в их иерархии (тип и соответствующие интерфейсы).

...