Jersey 2中的ResourceConfig类究竟是什么?

时间:2017-08-11 02:14:27

标签: jersey jax-rs jersey-2.0

我看过许多以

之类的东西开头的泽西教程
@ApplicationPath("services")
public class JerseyApplication extends ResourceConfig {
    public JerseyApplication() {
        packages("com.abc.jersey.services");
    }
}

没有解释ResourceConfig类究竟是什么。那么我在哪里可以找到它的文档,用法等?谷歌搜索“泽西资源配置”不会产生任何官方文档。

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

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

1 个答案:

答案 0 :(得分:109)

标准JAX-RS使用Application作为其配置类。 ResourceConfig 延伸 Application

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

  1. 仅使用web.xml
  2. 同时使用web.xml Application/ResourceConfig
  3. 只有Application/ResourceConfig类注明@ApplicationPath
  4. 仅使用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>告诉Jersey哪些软件包要扫描我们的@Path@Provider类,以便它们注册它们。

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

    同时使用web.xml和Application/ResourceConfig

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

    <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。而不是使用告诉Jersey要扫描哪个包的init-param,我们只使用packages()的便捷方法ResourceConfig

    我们还可以使用方法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规范中引入的内容,因此我们不能仅使用&#34; Java&#34;早期servlet容器中的配置。

    基本上发生的事情是初始化程序的实现者可以告诉servlet容器要查找的类,而servlet容器会将这些类传递给初始化程序onStartup()方法。在泽西岛初始化程序的实现中,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 {
        @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");
        }
    }
    

    除了更方便之外,还有一些帮助泽西配置应用程序的东西。

    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 constants并查找字符串值以jersey.config开头的那些属性。如果您使用的是web.xml,那么您将使用字符串值作为init-param param-name。如果您使用的是Java配置(ResourceConfig),那么您可以调用property(ServerProperties.SOME_CONF, value)