繁体   English   中英

引导JAX-RS(RESTEasy)

[英]Bootstrapping JAX-RS (RESTEasy)

我在嵌入式Web服务器(Jetty)中运行RESTEasy。

我的资源需要访问后备数据存储,其配置在用于启动我们的应用程序的命令行上传递。

理想情况下,我会在资源的构造函数中注入支持数据存储资源:

@Path("/")    
public class MappingService{
    private final RecordManager recman;

    public MappingService(RecordManager recman) {
        this.recman = recman;
    }

    @PUT
    @Path("/mapping/{key}")
    @Produces({MediaType.APPLICATION_JSON, "application/*+json"})
    public Response createMapping(@PathParam("key") String key, @QueryParam("val") String val) {
                // do stuff with recman ...
           }
    }

理想情况下,我将RecordManager对象配置在应用程序的其他位置,然后使其可用于MappingService构造函数。

我看到我可以使用Application对象返回特定的单例实例。 但看起来RESTEasy构造了Application对象本身 - 所以我没有看到任何方法将配置对象传递给Application单例。

那么:如何将外部实例化的对象传递给我的资源处理程序?


我发现这篇文章( 在JAX-RS请求之间共享变量 )描述了如何使用上下文监听器将对象添加到上下文并将其拉入资源处理程序 - 但这太可怕了 - 我必须采取应该是POJO的内容突然之间,我高度依赖它的容器。 请告诉我有更好的方法!

好的 - 我已经弄明白了 - 在这里记录以防万一其他人点击这个。

诀窍在于利用@Context注入来注入我想要的资源,而不是获取对servlet上下文的引用。 如果您对RestEASY引导过程有一些控制(而不是使用从web.xml中指定的类名构造的上下文侦听器进行引导,我们以编程方式注册上下文侦听器),则可以执行此操作。

我正在使用Jetty作为我的servlet容器。 这是我的主要方法:

public static void main(String[] args) throws Exception {
    final RecordManager recman = createRecordManager(args);

    Server server = new Server(DEFAULT_HTTP_PORT);
    try {

        WebAppContext webAppContext = new WebAppContext();
        webAppContext.setContextPath("/");
        webAppContext.setWar(WAR_LOCATION);

        webAppContext.addEventListener(new org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap(){
            @Override
            public void contextInitialized(ServletContextEvent event) {
                super.contextInitialized(event);
                deployment.getDispatcher().getDefaultContextObjects().put(RecordManager.class, recman);
            }
        });

        webAppContext.addServlet(org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.class, "/*");

        webAppContext.setServer(server);
        server.setHandler(webAppContext);

        server.start();

    } catch (Exception e) {
        logger.error("Error when starting", e);
        server.stop();
    } 
}

然后我的资源处理程序看起来像这样:

@Path("/")
public class MappingResource {

    private final RecordManager recman;

    public MappingResource(@Context RecordManager recman) { //<-- sweet! resource injection
        this.recman = recman;
    }


    @PUT
    @Path("/mapping/{key}")
    @Produces({MediaType.APPLICATION_JSON, "application/*+json"})
    public Response createMapping(@PathParam("key") String key, @QueryParam("val") String val) {
        // do something with recman, key and val
    }
}

为了彻底,这里是web.xml条目(这只是通用的resteasy配置):

<context-param>
    <param-name>resteasy.resources</param-name>
    <param-value>my.package.MappingService</param-value>
</context-param>

你可以使用Spring。

RESTEasy有一个使用Spring的例子 ,他们将DAO对象注入application.xml中的REST服务。 不是构造函数arg,而是作为字段

我将如下调整application.xml以使其适用于您的情况:

<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="recordManager" class="full.package.name.here.RecordManager"/>

    <bean id="mappingService"
          class="full.package.name.here.MappingService">
        <constructor-arg index="0" value="recordManager"/>
    </bean>

</beans>

在web.xml中使用初始化

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

<listener>
   <listener-class>org.jboss.resteasy.plugins.spring.SpringContextLoaderListener</listener-class>
</listener>

您需要添加这些类所在的resteasy-spring jar。

通常,RESTEasy Bootstrap侦听器会对类路径执行自己的组件扫描,并实例化使用@Path注释的类。 这妨碍了Spring的实例化。

以上设置的工作方式不同。 Spring初始化所有内容,包括您的服务。 然后,RESTEasy初始化开始,在Spring应用程序上下文中搜索使用@Path注释的bean,并将这些bean注册为REST服务。

不要使用new运算符实例化服务。 这将在Spring上下文之外创建新类,并且此类无法访问Spring manged bean,因此注入将无效(将保持为null)。

也许简单的singelton初始化。 像这样的东西:

RecordManagerMaster.initRecordManager(...);

消气:

RecordManager recman = RecordManagerMaster.getRecordManager();

您还可以将命令行参数添加为servlet上下文属性,然后通过注入(例如,在Application或资源中)访问servlet上下文。 这样可以避免使用任何RESTEasy / Jetty特定的功能(例如,如果你想使用Jersey),并且不需要WAR / WebAppContext

public static void main(String[] args) throws Exception  {
    Server server = new Server(0);
    ServletContextHandler handler = new ServletContextHandler(server, "/");
    handler.setAttribute("main.args", ImmutableList.copyOf(args));
    ServletHolder holder = new ServletHolder(new HttpServletDispatcher());
    holder.setInitParameter("javax.ws.rs.Application", MyApplication.getName());
    handler.addServlet(holder, "/*");
    server.start();
    server.join();
}

public class MyApplication extends Application {
    public PubSubApplication(@Context ServletContext servletContext) throws Exception {
        String[] args = servletContext.getAttribute("main.args");
        // do stuff with args...
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM