【问题标题】:What exactly is the ResourceConfig class in Jersey 2?Jersey 2 中的 ResourceConfig 类到底是什么?
【发布时间】:2018-01-19 10:10:25
【问题描述】:

我看过很多以类似开头的 Jersey 教程

@ApplicationPath("services")
public class JerseyApplication extends ResourceConfig {
    public JerseyApplication() {
        packages("com.abc.jersey.services");
    }
}

没有解释ResourceConfig 类到底是什么。那么我在哪里可以找到它的文档、用法等呢?谷歌搜索“jersey resourceconfig”不会产生任何官方文档。

我对这个类及其用法的一些问题是:

  • 我可以在ResourceConfig 的子类中做些什么?
  • 我是否需要在某处注册ResourceConfig 的子类以便可以找到它或者它会被Jersey 自动检测到?
  • 如果自动检测到子类,如果我有多个 ResourceConfig 子类会怎样?
  • ResourceConfig 的用途与web.xml 文件的用途相同吗?如果是这样,如果我在我的项目中同时拥有这两者会发生什么?其中一个是否优先于另一个?

【问题讨论】:

    标签: jersey jax-rs jersey-2.0


    【解决方案1】:

    标准 JAX-RS 使用 Application 作为其配置类。 ResourceConfig 扩展 Application.

    有三种主要方式(在 servlet 容器中)来配置 Jersey (JAX-RS):

    1. 只有 web.xml
    2. 同时使用 web.xml Application/ResourceConfig
    3. 只有一个Application/ResourceConfig 类用@ApplicationPath 注释。

    只有 web.xml

    可以以标准的 JAX-RS 方式配置应用程序,但以下是特定于 Jersey 的

    <web-app>
        <servlet>
            <servlet-name>jersey-servlet</servlet-name>
            <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
            <init-param>
                <param-name>jersey.config.server.provider.packages</param-name>
                <param-value>com.mypackage.to.scan</param-value>
            </init-param>
        </servlet>
        ...
        <servlet-mapping>
            <servlet-name>jersey-servlet</servlet-name>
            <url-pattern>/api/*</url-pattern>
        </servlet-mapping>
        ...
    </web-app>
    

    由于 Jersey 在 servlet 容器中运行,因此 Jersey 应用程序作为 servlet 运行是正确的。处理传入请求的 Jersey Servlet 是 ServletContainer。所以在这里我们将其声明为&lt;servlet-class&gt;。我们还配置了一个 &lt;init-param&gt; 告诉 Jersey 扫描哪些包以查找我们的 @Path@Provider 类,以便它可以注册它们。

    在底层,Jersey 实际上会创建一个ResourceConfig 实例,因为它是用来配置应用程序的。然后它将注册它通过包扫描发现的所有类。

    同时使用 web.xml 和 Application/ResourceConfig

    如果我们想通过ApplicationResourceConfig 子类以编程方式配置我们的应用程序,我们可以通过对上述web.xml 进行一次更改来实现。我们没有设置一个 init-param 来扫描包,而是使用一个 init-param 来声明我们的 Application/ResourceConfig 子类。

    <servlet>
        <servlet-name>jersey-servlet</servlet-name>
        <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
        <init-param>
            <param-name>javax.ws.rs.Application</param-name>
            <param-value>com.example.JerseyApplication</param-value>
        </init-param>
        <servlet-mapping>
            <servlet-name>jersey-servlet</servlet-name>
            <url-pattern>/api/*</url-pattern>
        </servlet-mapping>
    </servlet>
    
    package com.example;
    
    public class JerseyApplication extends ResourceConfig {
        public JerseyApplication() {
            packages("com.abc.jersey.services");
        }
    }
    

    在这里,我们使用 ResourceConfig 子类的完全限定名称配置 init-param javax.ws.rs.Application。而不是使用init-param 告诉Jersey 要扫描哪个包,我们只使用ResourceConfig 的便捷方法packages()

    我们还可以使用register()property() 方法来注册资源和提供者,以及配置Jersey 属性。使用property() 方法,可以配置为init-param 的任何内容也可以使用property() 方法进行配置。例如,我们可以不调用packages(),而是这样做

    public JerseyApplication() {
        property("jersey.config.server.provider.packages",
                 "com.mypackage.to.scan");
    }
    

    只有Application/ResourceConfig

    如果没有 web.xml,Jersey 需要一种方法来提供 servlet 映射。我们使用@ApplicationPath 注释来做到这一点。

    // 'services', '/services', or '/services/*'
    // is all the same. Jersey will change it to be '/services/*'
    @ApplicationPath("services")
    public class JerseyApplication extends ResourceConfig {
        public JerseyApplication() {
            packages("com.abc.jersey.services");
        }
    }
    

    这里用@ApplicationPath,就像我们在web.xml中配置了servlet映射

    <servlet-mapping>
        <servlet-name>JerseyApplication</servlet-name>
        <url-pattern>/services/*</url-pattern>
    </servlet-mapping>
    

    当仅使用 Java 代码进行配置时,Jersey 需要通过某种方式发现我们的配置类。这是通过使用ServletContanerInitializer 完成的。这是 Servlet 3.0 规范中引入的内容,因此我们不能在早期的 servlet 容器中使用“仅限 Java”配置。

    基本上,初始化程序的实现者可以告诉 servlet 容器要查找哪些类,然后 servlet 容器会将这些类传递给初始化程序 onStartup() 方法。在 Jersey 的初始化器实现中,Jersey 将其配置为查找 Application 类和带有 @ApplicationPath 注释的类。请参阅this post 了解更多说明。因此,当 servlet 容器启动应用程序时,Jersey 的初始化程序将通过我们的 Application/ResourceConfig 类。

    我可以在 ResourceConfig 的子类中做些什么

    看看javadoc。它主要只是注册课程。你不需要做太多其他事情。您将使用的主要方法是register()packages()property() 方法。 register() 方法允许您手动注册资源和提供者的类和实例。前面讨论过的packages() 方法列出了您希望Jersey 扫描@Path@Provider 类并为您注册它们的包。而property() 方法允许你设置一些configurable properties 1

    ResourceConfig 只是一个便利类。请记住,它扩展了Application,所以我们甚至可以使用标准的Application

    @ApplicationPath("/services")
    public class JerseyApplication extends Application {
    
        private final Set<Class<?>> classes;
        private final Set<Object> singletons;
    
        public JerseyApplication() {
            // configure in constructor as Jersey
            // may call the getXxx methods multiple times
    
            this.classes = new HashSet<>();
            this.classes.add(MyResource.class);
    
            this.singletons = new HashSet<>();
            this.singletons.add(new MyProvider());
        }
    
        @Override
        public Set<Class<?>> getClasses() {
            return this.classes;
        }
    
        @Override
        public Set<Object> getSingletons() {
            return this.singletons;
        }
    
        @Override
        public Map<String, Object> getProperties() {
            final Map<String, Object> properties = new HashMap<>();
            properties.put("jersey.config.server.provider.packages",
                           "com.mypackage.to.scan");
            return properties;
        }
    }
    

    有了ResourceConfig,我们就可以了

    public class JerseyApplication extends ResourceConfig {
        public JerseyApplication() {
            register(MyResource.class);
            register(new MyProvider());
            packages("com.mypackages.to.scan");
        }
    }
    

    除了更方便之外,还有一些事情可以帮助 Jersey 配置应用程序。

    SE 环境

    以上所有示例都假设您在已安装的服务器环境中运行,例如雄猫。但您也可以在 SE 环境中运行应用程序,在其中运行嵌入式服务器并从 main 方法启动应用程序。您有时会在四处搜索信息时看到这些示例,所以我想展示一下它们的外观,这样如果您遇到这种情况,您不会感到惊讶,并且知道它与您的设置有何不同。

    所以有时你会看到这样的例子

    ResourceConfig config = new ResourceConfig();
    config.packages("com.my.package");
    config.register(SomeFeature.class);
    config.property(SOME_PROP, someValue);
    

    这里最有可能发生的情况是该示例使用了嵌入式服务器,例如 Grizzly。启动服务器的其余代码可能类似于

    public static void main(String[] args) {
        ResourceConfig config = new ResourceConfig();
        config.packages("com.my.package");
        config.register(SomeFeature.class);
        config.property(SOME_PROP, someValue);
    
        String baseUri = "http://localhost:8080/api/";
        HttpServer server = GrizzlyHttpServerFactory
                .createHttpServer(URI.create(baseUri), config);
        server.start();
    }
    

    所以在这个例子中,有一个独立的服务器正在启动,ResourceConfig 用于配置 Jersey。这里和前面的例子不同的是,在这个例子中,我们没有扩展ResourceConfig,而是仅仅实例化它。如果我们这样做也不会有什么不同

    public class JerseyConfig extends ResourceConfig {
        public JerseyConfig() {
            packages("com.my.package");
            register(SomeFeature.class);
            property(SOME_PROP, someValue);
        }
    }
    
    HttpServer server = GrizzlyHttpServerFactory
                .createHttpServer(URI.create(baseUri), new JerseyConfig());
    

    假设您正在阅读一些教程,它显示了一个独立应用程序的配置,他们在其中实例化了ResourceConfig。但是您在已安装的 servlet 容器中运行您的应用程序,并且一直在使用您扩展 ResourceConfig 的早期配置。那么现在您知道区别是什么以及您需要进行哪些更改。我见过人们做一些非常奇怪的事情,因为他们不理解这种差异。例如,我看到有人在资源类中实例化 ResourceConfig。所以这就是我添加这个额外的小片段的原因;所以你不会犯同样的错误。


    脚注

    1。有许多不同的可配置属性。 ServerProperties 的链接只是一些一般属性。还有与特定功能相关的不同属性。文档应在与该功能相关的文档部分中提及这些属性。对于所有可配置属性的完整列表,您可以查看所有Jersey constants 并查找字符串值以jersey.config 开头的那些。如果您使用的是 web.xml,那么您将使用字符串值作为 init-param param-name。如果您使用的是 Java 配置 (ResourceConfig),那么您将调用 property(ServerProperties.SOME_CONF, value)

    【讨论】:

    • 嗨,保罗,谢谢你的详细回答,我希望你能把我推向正确的方向。请参阅我的问题stackoverflow.com/questions/70646059/…
    • 如果您使用 web.xml & ResourceConfig 解决方案并且您使用 Jersey 3.x - 您需要将 jakarta.ws.rs.Application 设置为 param-name
    猜你喜欢
    • 1970-01-01
    • 2016-03-16
    • 2017-07-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-15
    • 2015-09-20
    • 1970-01-01
    相关资源
    最近更新 更多