Jersey 2 中的 ResourceConfig 类到底是啥?
Posted
技术标签:
【中文标题】Jersey 2 中的 ResourceConfig 类到底是啥?【英文标题】: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
文件的用途相同吗?如果是这样,如果我在我的项目中同时拥有这两者会发生什么?其中一个是否优先于另一个?
【问题讨论】:
【参考方案1】:标准 JAX-RS 使用 Application
作为其配置类。 ResourceConfig
扩展 Application
.
有三种主要方式(在 servlet 容器中)来配置 Jersey (JAX-RS):
-
只有 web.xml
同时使用 web.xml 和
Application/ResourceConfig
类
只有一个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>
告诉 Jersey 扫描哪些包以查找我们的 @Path
和 @Provider
类,以便它可以注册它们。
在底层,Jersey 实际上会创建一个ResourceConfig
实例,因为它是用来配置应用程序的。然后它将注册它通过包扫描发现的所有类。
同时使用 web.xml 和 Application/ResourceConfig
如果我们想通过Application
或ResourceConfig
子类以编程方式配置我们的应用程序,我们可以通过对上述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)
【讨论】:
嗨,保罗,谢谢你的详细回答,我希望你能把我推向正确的方向。请参阅我的问题***.com/questions/70646059/… 如果您使用 web.xml & ResourceConfig 解决方案并且您使用 Jersey 3.x - 您需要将jakarta.ws.rs.Application
设置为 param-name
!以上是关于Jersey 2 中的 ResourceConfig 类到底是啥?的主要内容,如果未能解决你的问题,请参考以下文章
如何将Swagger no config设置与Jersey 2集成
JAX-RS (Jersey 2) - 使用 JSR 250 注释的授权