Jersey Rest 服务的 ResourceConfig 和 ServletContextListener 之间的区别

Difference between ResourceConfig and ServletContextListener for Jersey Rest Service

我想初始化 Jersey Rest 服务并引入一个全局应用程序范围的变量,该变量应在应用程序启动时计算,并且应在每个 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 中。所以我的问题是哪种方式是最好的做法。谢谢!

您可以通过调用 property( key, value ).

ResourceConfig 中设置 属性
public MyApplication() {
    property("MyProp", "MyValue");
}

在您的资源 class 中,您只能注入超级抽象 class javax.ws.rs.core.ApplicationResourceConfig 从中扩展。

然后你可以做的是调用标准 Application API 方法之一来获取设置属性。该方法当然被命名为 getProperties(),其中 returns 是一个属性映射。

@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");
    }
}

另请参阅:

  • Using a custom hk2 InjectionResolver to inject application configuration 一些其他有趣的方法来注入值而不是必须从 ApplicationConfiguration
  • 中检索它

对不起,如果调用 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 在这里设置为 "resources" ?

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

编辑: 对于关注我们讨论的人,solution/problem 如下。加上我的servlet部署部分web.xml,首先我写错了

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

删除 * 并将 url 模式更改为 <url-pattern>/</url-pattern>(不带 *)并分别更改

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

终于解决了。因此,ApplicationPath 必须与 web.xml 中的 Servlet-Url 中的相同,以便正确完成方法 class 中的注入。