泽西岛2中的ResourceConfig类到底是什么?


72

我看过很多Jersey教程,它们都以类似

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

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

我对此类及其用法的一些疑问是:

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

Answers:


185

标准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。因此,在这里我们将其声明为<servlet-class>。我们还配置了一个自动<init-param>柜员机来扫描我们的@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");
    }
}

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

我们也可以使用的方法register()property()注册资源和提供者,以及配置泽西属性。使用该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。有关更多说明,请参见此帖子。因此,当servlet容器启动应用程序时,Jersey的初始化程序将通过我们的Application/ResourceConfig类。

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

只要看看javadoc即可。它主要只是课程注册。您不需要做很多其他事情。您将使用的主要方法是register()packages()property()方法。该register()方法使您可以手动注册资源和提供程序的类和实例。packages()前面讨论的方法列出了希望Jersey扫描的软件包,@Path@Provider分类并为您注册。并且该property()方法允许您设置一些可配置的属性1

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

@ApplicationPath("/services")
public class JerseyApplication extends Application {
    @Override
    public Set<Class<?>> getClasses() {
        final Set<Class<?>> classes = new HashSet<>();
        classes.add(MyResource.class);
        return classes;
    }
    @Override
    public Set<Object> getSingletons() {
        final Set<Object> singletons = new HashSet<>();
        singletons.add(new MyProvider());
        return 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环境

上面的所有示例均假定您正在已安装的服务器环境中运行,例如Tomcat。但是,您也可以在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常量,并查找字符串值以开头的常量jersey.config。如果您使用的是web.xml,则可以将字符串值用作init-param param-name。如果您使用的是Java config(ResourceConfig),则可以调用property(ServerProperties.SOME_CONF, value)


4
感谢您的答复!这为我清理了很多东西。
下巴

1
漂亮的答案-太棒了!
Reuben Tanner

1
从基础知识出发,非常详尽而详尽的解释。谢谢 !
Mahesh

惊人的解释。SOF上最好的之一!感谢您分享这些知识。
IllegalSkillsException

简明扼要,这是一个很好的解释。清除了许多对Jax-rs部署的挥之不去的疑问,非常感谢……!
Roshan
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.