标准 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)