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

Chi*_*hin 53 jax-rs jersey jersey-2.0

我看过很多以类似的东西开头的泽西教程

@ApplicationPath("services")
public class JerseyApplication extends ResourceConfig {
    public JerseyApplication() {
        packages("com.abc.jersey.services");
    }
}
Run Code Online (Sandbox Code Playgroud)

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

关于这个课程及其用法的一些问题是:

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

Pau*_*tha 139

标准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>
Run Code Online (Sandbox Code Playgroud)

由于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>
Run Code Online (Sandbox Code Playgroud)
package com.example;

public class JerseyApplication extends ResourceConfig {
    public JerseyApplication() {
        packages("com.abc.jersey.services");
    }
}
Run Code Online (Sandbox Code Playgroud)

在这里,我们init-param javax.ws.rs.Application使用ResourceConfig子类的完全限定名称进行配置.而不是使用init-param它告诉泽西哪个包(一个或多个)进行扫描,我们只需使用便捷方法packages()ResourceConfig.

我们还可以使用这些方法register()property()注册资源和提供程序,以及配置Jersey属性.使用该property()方法,init-param还可以使用该property()方法配置任何可以配置为的方法.例如packages(),我们可以做而不是打电话

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

只有 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");
    }
}
Run Code Online (Sandbox Code Playgroud)

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

<servlet-mapping>
    <servlet-name>JerseyApplication</servlet-name>
    <url-pattern>/services/*</url-pattern>
</servlet-mapping>
Run Code Online (Sandbox Code Playgroud)

当仅使用Java代码进行配置时,Jersey需要有一些方法来发现我们的配置类.这是通过使用a来完成的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;
    }
}
Run Code Online (Sandbox Code Playgroud)

有了ResourceConfig,我们就是这么做的

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

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

SE环境

上面的所有示例都假设您在已安装的服务器环境中运行,例如Tomcat.但您也可以在SE环境中运行应用程序,在该环境中运行嵌入式服务器并从main方法启动应用程序.在搜索信息时,您有时会看到这些示例,因此我想展示它的外观,以便当您遇到这些时,您不会感到惊讶并且知道它与您的设置有何不同.

所以有时你会看到一个例子

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

这里最有可能发生的是该示例使用的是嵌入式服务器,如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();
}
Run Code Online (Sandbox Code Playgroud)

因此,在此示例中,有一个独立服务器正在启动,并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());
Run Code Online (Sandbox Code Playgroud)

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


脚注

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

  • 谢谢你的精彩回答!这为我清理了很多东西. (4认同)
  • 如果您使用 web.xml 和 ResourceConfig 解决方案并且使用 Jersey 3.x - 您需要将 `jakarta.ws.rs.Application` 设置为 `param-name`! (3认同)