【问题标题】:RESTEasy will not map my Spring bean with custom Spring ContextLoaderRESTEasy 不会用自定义 Spring ContextLoader 映射我的 Spring bean
【发布时间】:2011-07-25 15:16:16
【问题描述】:
  • RESTEasy 2.0.1GA
  • Java 1.6
  • 春季 3.0.3

我已尽我所能,但无法完全确定正在发生的事情。我有一个 Spring MVC 应用程序,但是我希望在 Spring MVC 应用程序之外 有一些可用的 RESTEasy 端点,但在同一个容器中,最终能够连接到同一个 bean。

作为第一步,我只是尝试在容器内建立 RESTEasy,为来自 Spring 配置的 bean 的请求提供服务。我已经尝试了说明中的样板,也尝试了手动设置,但无济于事。

@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>

根据文档,我所要做的就是“通过分配 org.jboss.resteasy.plugins.spring.SpringBeanProcessor 的实例手动注册 RESTeasy BeanFactoryPostProcessor”。我相信这个 spring 配置可以做到这一点。

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 向我展示映射,它似乎只是没有发现我的 bean。

如果我通过 resteasy.resources 上下文参数显式映射它,它可以工作,但显然无法访问自动连接的 Spring bean。

还有什么我可以尝试的吗?我在整个 RESTEasy 代码库上有调试日志,但没有收到任何消息。我还确认 Spring 实际上正在创建我的 bean,所以只是 RESTEasy 没有找到它。

【问题讨论】:

  • Spring MVC 有自己的 REST 风格的框架。为什么不直接使用它,避免整个问题?
  • 与 JAX-RS 相比,Spring MVC “rest”框架非常弱且功能匮乏
  • 如果您的代码示例就是这样的例子,那么它很容易做到。
  • 戴夫,你能分享一下正确的解决方案吗?谢谢。

标签: java spring spring-mvc resteasy


【解决方案1】:

您的资源类需要使用@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 通过在SpringContextLoader 中注册ApplicationListener 来代表它:

  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 遍历所有 Spring bean 并向 RESTeasy 注册那些在其层次结构(类型及其相应接口)的某处具有 @Path 注释的那些。

【讨论】:

  • 代码粘贴旧;我在顶部使用 @Path 并且不再具有该路径参数。你能解释一下你发布的代码的上下文吗?我是否需要在我的应用程序中某处这样的代码,如果需要,在哪里?我正在我的应用程序上下文中实例化 RESTEasy 的 SpringBeanProcessor……它似乎没有做任何事情
  • 好吧,没关系,这段代码很有帮助;我没有正确阅读代码库,并且在我的问题中忘记了一些信息。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-02-04
  • 2014-11-13
  • 2017-03-22
  • 1970-01-01
  • 2011-03-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多