Jersey 2 中的 ResourceConfig class 到底是什么?
What exactly is the ResourceConfig class in Jersey 2?
我看过很多以
开头的 Jersey 教程
@ApplicationPath("services")
public class JerseyApplication extends ResourceConfig {
public JerseyApplication() {
packages("com.abc.jersey.services");
}
}
没有解释 ResourceConfig
class 到底是什么。那么在哪里可以找到它的文档、用法等呢?谷歌搜索 "jersey resourceconfig" 没有得到任何官方文档。
关于这个 class 及其用法的一些问题是:
- 我可以在
ResourceConfig
的子 class 中做什么?
- 我是否需要在某处注册
ResourceConfig
的子 class 以便可以找到它,或者它是否会被 Jersey 自动检测到?
- 如果自动检测到子class 如果我有多个
ResourceConfig
的子class 会怎样?
ResourceConfig
的用途是否与 web.xml
文件相同?如果是这样,如果我在我的项目中同时拥有两者会怎样?其中一个优先于另一个吗?
标准 JAX-RS 使用 Application
as its configuration class. ResourceConfig
扩展 Application
.
配置 Jersey (JAX-RS) 的三种主要方式(在 servlet 容器中):
- 只有web.xml
- web.xml和和
Application/ResourceConfig
class
- 只有
Application/ResourceConfig
class 注释 @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 运行s 在一个 servlet 容器中,那么 Jersey 应用程序 运行s 作为一个 servlet 是正确的。处理传入请求的 Jersey Servlet 是 ServletContainer
。所以在这里我们声明它为<servlet-class>
。我们还配置了一个 <init-param>
告诉 Jersey 哪些包要扫描我们的 @Path
和 @Provider
classes 以便它可以注册它们。
在幕后,Jersey 实际上会创建一个 ResourceConfig
实例,因为它是用来配置应用程序的。然后它将注册它通过包扫描发现的所有 classes。
web.xml 和 Application/ResourceConfig
如果我们想以编程方式使用 Application
或 ResourceConfig
subclass 配置我们的应用程序,我们可以通过对上述 web.xml 的一个更改来实现。我们没有设置 init-param 来扫描包,而是使用 init-param 来声明我们的 Application/ResourceConfig
subclass.
<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
subclass 的完全限定名称配置 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 需要某种方式来发现我们的配置 class。这是通过使用 ServletContanerInitializer
完成的。这是 Servlet 3.0 规范中引入的内容,因此我们不能在早期的 servlet 容器中使用“Java only”配置。
基本上发生的事情是初始化器的实现者可以告诉 servlet 容器要查找的 classes,然后 servlet 容器将那些 classes 传递给初始化器 onStartup()
方法。在 Jersey 的初始化程序实现中,Jersey 将其配置为查找 Application
classes 和 classes 注释为 @ApplicationPath
。有关详细说明,请参阅 。因此,当 servlet 容器启动应用程序时,Jersey 的初始化程序将通过我们的 Application/ResourceConfig
class.
在 ResourceConfig
的 subclass 里面可以做什么
看看javadoc. Its mostly just registration of classes. Not much else you need to do with it. The main methods you will be using are the register()
, packages()
, and property()
methods. The register()
method lets you manually register classes and instances of resources and providers manually. The packages()
method, discussed earlier, lists the package(s) you want Jersey to scan for @Path
and @Provider
classes and register them for you. And the property()
method allows you to set some configurable properties1.
ResourceConfig
只是为了方便class。请记住,它扩展了 Application
,因此我们甚至可以使用标准的 Application
class
@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 环境
以上所有示例都假设您 运行 在已安装的服务器环境中,例如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
。那么现在您知道有什么区别以及需要进行哪些更改。我见过人们做一些非常奇怪的事情,因为他们不理解这种差异。例如,我看到有人在资源 class 中实例化 ResourceConfig
。所以这就是为什么我添加了这个额外的小块;所以你不会犯同样的错误。
脚注
1.有许多不同的可配置属性。 link 到 ServerProperties
are just some general properties. There are also different properties related to specific features. The documentation should mention these properties in the section of the docs related to that feature. For a complete list of all configurable properties, you can look at all the Jersey constants 并查找字符串值以 jersey.config
开头的字符串。如果您使用 web.xml,那么您将使用字符串值作为 init-param
param-name
。如果您使用 Java 配置 (ResourceConfig
),那么您将调用 property(ServerProperties.SOME_CONF, value)
我看过很多以
开头的 Jersey 教程@ApplicationPath("services")
public class JerseyApplication extends ResourceConfig {
public JerseyApplication() {
packages("com.abc.jersey.services");
}
}
没有解释 ResourceConfig
class 到底是什么。那么在哪里可以找到它的文档、用法等呢?谷歌搜索 "jersey resourceconfig" 没有得到任何官方文档。
关于这个 class 及其用法的一些问题是:
- 我可以在
ResourceConfig
的子 class 中做什么? - 我是否需要在某处注册
ResourceConfig
的子 class 以便可以找到它,或者它是否会被 Jersey 自动检测到? - 如果自动检测到子class 如果我有多个
ResourceConfig
的子class 会怎样? ResourceConfig
的用途是否与web.xml
文件相同?如果是这样,如果我在我的项目中同时拥有两者会怎样?其中一个优先于另一个吗?
标准 JAX-RS 使用 Application
as its configuration class. ResourceConfig
扩展 Application
.
配置 Jersey (JAX-RS) 的三种主要方式(在 servlet 容器中):
- 只有web.xml
- web.xml和和
Application/ResourceConfig
class - 只有
Application/ResourceConfig
class 注释@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 运行s 在一个 servlet 容器中,那么 Jersey 应用程序 运行s 作为一个 servlet 是正确的。处理传入请求的 Jersey Servlet 是 ServletContainer
。所以在这里我们声明它为<servlet-class>
。我们还配置了一个 <init-param>
告诉 Jersey 哪些包要扫描我们的 @Path
和 @Provider
classes 以便它可以注册它们。
在幕后,Jersey 实际上会创建一个 ResourceConfig
实例,因为它是用来配置应用程序的。然后它将注册它通过包扫描发现的所有 classes。
web.xml 和 Application/ResourceConfig
如果我们想以编程方式使用 Application
或 ResourceConfig
subclass 配置我们的应用程序,我们可以通过对上述 web.xml 的一个更改来实现。我们没有设置 init-param 来扫描包,而是使用 init-param 来声明我们的 Application/ResourceConfig
subclass.
<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
subclass 的完全限定名称配置 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-mapping>
<servlet-name>JerseyApplication</servlet-name>
<url-pattern>/services/*</url-pattern>
</servlet-mapping>
当仅使用 Java 代码进行配置时,Jersey 需要某种方式来发现我们的配置 class。这是通过使用 ServletContanerInitializer
完成的。这是 Servlet 3.0 规范中引入的内容,因此我们不能在早期的 servlet 容器中使用“Java only”配置。
基本上发生的事情是初始化器的实现者可以告诉 servlet 容器要查找的 classes,然后 servlet 容器将那些 classes 传递给初始化器 onStartup()
方法。在 Jersey 的初始化程序实现中,Jersey 将其配置为查找 Application
classes 和 classes 注释为 @ApplicationPath
。有关详细说明,请参阅 Application/ResourceConfig
class.
在 ResourceConfig
的 subclass 里面可以做什么看看javadoc. Its mostly just registration of classes. Not much else you need to do with it. The main methods you will be using are the register()
, packages()
, and property()
methods. The register()
method lets you manually register classes and instances of resources and providers manually. The packages()
method, discussed earlier, lists the package(s) you want Jersey to scan for @Path
and @Provider
classes and register them for you. And the property()
method allows you to set some configurable properties1.
ResourceConfig
只是为了方便class。请记住,它扩展了 Application
,因此我们甚至可以使用标准的 Application
class
@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 环境
以上所有示例都假设您 运行 在已安装的服务器环境中,例如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
。那么现在您知道有什么区别以及需要进行哪些更改。我见过人们做一些非常奇怪的事情,因为他们不理解这种差异。例如,我看到有人在资源 class 中实例化 ResourceConfig
。所以这就是为什么我添加了这个额外的小块;所以你不会犯同样的错误。
脚注
1.有许多不同的可配置属性。 link 到 ServerProperties
are just some general properties. There are also different properties related to specific features. The documentation should mention these properties in the section of the docs related to that feature. For a complete list of all configurable properties, you can look at all the Jersey constants 并查找字符串值以 jersey.config
开头的字符串。如果您使用 web.xml,那么您将使用字符串值作为 init-param
param-name
。如果您使用 Java 配置 (ResourceConfig
),那么您将调用 property(ServerProperties.SOME_CONF, value)