【问题标题】:Difference between ResourceConfig and ServletContextListener for Jersey Rest ServiceJersey Rest 服务的 ResourceConfig 和 ServletContextListener 之间的区别
【发布时间】:2015-09-21 08:59:26
【问题描述】:

我想初始化 Jersey Rest 服务并引入一个全局应用程序范围的变量,该变量应该在应用程序启动时计算,并且应该在每个休息资源和每个方法中都可用(这里由整数 globalAppValue=17 表示,但以后会是一个复杂的对象)。

为了在启动时初始化服务并计算一次值,我发现了两种做法:通用 ServletContextListener 和 Jersey ResourceConfig 方法。但是我一直不明白他们两个有什么区别?两种方法都在启动时触发(打印两个 System.out 消息)。

这是我的 ServletContextListener 的实现,它工作正常:

public class LoadConfigurationListener implements ServletContextListener
{
    private int globalAppValue = 17;

    @Override
    public void contextDestroyed (ServletContextEvent event)
    {
    }

    @Override
    public void contextInitialized (ServletContextEvent event)
    {
        System.out.println ("ServletContext init.");

        ServletContext context = event.getServletContext ();
        context.setAttribute ("globalAppValue", globalAppValue);
    }
}

这是 Jersey Rest ResourceConfig 方法的实现,其中 ServletContext 不可用。以后也不能通过注入资源方法来获得此应用程序对象:

@ApplicationPath("Resources")
public class MyApplication extends ResourceConfig
{
    @Context
    ServletContext context;

    private int globalAppValue = 17;

    public MyApplication () throws NamingException
    {
        System.out.println ("Application init.");

        // returns NullPointerException since ServletContext is not injected
        context.setAttribute ("globalAppValue", 17);
    }

    public int getAppValue ()
    {
        return globalAppValue;
    }
}

这是我希望在资源方法中访问全局值的方式:

@Path("/")
public class TestResource
{
    @Context
    ServletContext context;
    @Context
    MyApplication application;

    @Path("/test")
    @GET
    public String sayHello () throws SQLException
    {
        String result = "Hello World: ";

        // returns NullPointerException since application is not injected
        result += "globalAppValue=" + application.getAppValue ();

        // works!
        result += "contextValue=" + context.getAttribute ("globalAppValue");

        return result;
    }
}

因此,虽然经典的 ServletContextListener 工作正常,但我在使用 ResourceConfig/Application 时遇到了一些问题,但我更喜欢这种方式,因为它似乎更本机地集成到 Jersey 中。所以我的问题是哪种方式是最好的做法。谢谢!

【问题讨论】:

    标签: java rest jersey


    【解决方案1】:

    您可以通过调用property( key, value )ResourceConfig 中设置一个属性。

    public MyApplication() {
        property("MyProp", "MyValue");
    }
    

    在您的资源类中,您只能注入超抽象类javax.ws.rs.core.ApplicationResourceConfig 是从该类扩展而来。

    然后您可以调用其中一种标准的Application API 方法来获取设置属性。该方法当然被命名为getProperties(),它返回一个属性映射。

    @Path("/")
    public class TestResource
    {
        @Context
        Application application;
    
        @GET
        public String get() {
            String value = (String)application.getProperties().get("MyProp");
        }
    }
    

    同样通过在ResourceConfig 上使用property 方法,该属性被放入一个全局javax.ws.rs.core.Configuration 对象中,该对象也是可注入的。所以你可以注入Configuration,而不是Application

    @Path("/")
    public class TestResource
    {
        @Context
        Configuration config;
    
        @GET
        public String get() {
            String value = (String)config.getProperty("MyProp");
        }
    }
    

    另请参阅:

    【讨论】:

    • 谢谢,这样行得通!但是在 Jersey Rest web 服务中应该首选什么方法呢? ServletContextListener 还是 Application-ResourceConfig 方式?
    • 我更喜欢穿泽西。如果不需要,则无需涉及 servlet 容器。它就像穷人的依赖注入。 Jersey 具备处理 DI 的所有能力。
    • 我似乎又被卡住了:当我在public class Application extends ResourceConfig 的构造函数中使用property ("value", 17); 时,我可以立即在那里重新读取该属性,但不能在我的资源方法中。注入@Context Application application; 有效(应用程序不为空),但 application.getProperties () 返回空值。那么在 Application 类中是否有任何特殊的注释要设置?您能否将前面示例中的 Application 类扩展为带有注释和导入的完整类?
    • 这正是您在原始帖子中的样子。 MyApplication extends ResourceConfig。除了@ApplicationPath 没有其他注释
    • 你能看看下面的答案(我的代码)吗?
    【解决方案2】:

    抱歉,如果调用 GET /test/,这会产生“value=null”作为输出。

    package rest;
    
    import javax.ws.rs.GET;
    import javax.ws.rs.Path;
    import javax.ws.rs.core.Application;
    import javax.ws.rs.core.Context;
    
    @Path("/test")
    public class TestResource
    {
        @Context
        Application application;
    
        @GET
        public String sayHello () 
        {
            String result = "value=" + application.getProperties ().get ("value");
    
            return result;
        }
    }
    

    ApplicationPath 在此处设置为“资源”?

    package rest;
    
    import javax.ws.rs.ApplicationPath;
    
    import org.glassfish.jersey.server.ResourceConfig;
    
    @ApplicationPath("resources")
    public class MyApplication extends ResourceConfig
    {
        public MyApplication ()
        {
            property ("value", 17);
            System.out.println (getProperties ());
        }
    }
    

    编辑:对于那些关注我们讨论的人,解决方案/问题如下。使用我的 web.xml 的 servlet 部署部分,首先我写错了

    <servlet-mapping>
        <servlet-name>Jersey REST Service</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>
    

    删除 * 并将 url-pattern 更改为 &lt;url-pattern&gt;/&lt;/url-pattern&gt;(不带 *)并分别更改后

    @ApplicationPath("/")
    public class MyApplication extends ResourceConfig
    

    终于成功了。因此 ApplicationPath 必须与 web.xml 中的 Servlet-Url 相同,才能正确完成方法类中的注入。

    【讨论】:

    • 我不知道它是否适合我。在我发布答案之前进行了测试。现在再次确定。正在打印 S.o.p(getProperties())?
    • 可能需要 web.xml 或 context.xml 中的一些其他资源或配置?
    • 别无其他。你试过Configuration吗?
    • 一些问题:config.properties 为空。
    • 那我不知道还能告诉你什么。两者都适合我
    猜你喜欢
    • 2010-11-29
    • 2015-01-05
    • 1970-01-01
    • 2012-03-19
    • 2017-01-06
    • 2013-09-24
    • 2015-01-05
    • 2018-09-01
    • 2017-10-02
    相关资源
    最近更新 更多