标准的JAX-RS使用Application
作为其配置类。ResourceConfig
扩展Application
。
在servlet容器中,有三种主要方法来配置Jersey(JAX-RS):
- 仅使用web.xml
- 同时使用web.xml 和一个
Application/ResourceConfig
类
- 仅使用带有
@ApplicationPath
注释的Application/ResourceConfig
类。
仅使用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
实例,因为它用于配置应用程序。然后它将注册通过包扫描发现的所有类。
如果我们想使用
Application
或
ResourceConfig
子类以编程方式配置我们的应用程序,我们可以对上述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");
}
}
在这里,我们通过完全限定名称配置
ResourceConfig
子类的
init-param
javax.ws.rs.Application
。而且,我们不使用告诉Jersey要扫描哪些包的
init-param
,我们只是使用
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-mapping。我们使用@ApplicationPath
注解来实现这一点。
@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
当仅使用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() {
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
。现在你知道了区别和需要做出的更改。我曾经看到有人因为不理解这个区别而做出了一些非常奇怪的事情。例如,我曾看到有人在资源类中实例化了
ResourceConfig
。所以我添加了这个额外的小部分,让你不会犯同样的错误。
脚注
1. 有许多不同的可配置属性。ServerProperties
的链接只是一些通用属性。还有与特定功能相关的不同属性。文档应在相关功能的部分中提到这些属性。要获取所有可配置属性的完整列表,可以查看所有Jersey常量,并查找字符串值以 jersey.config
开头的常量。如果您使用的是 web.xml,则将字符串值用作 init-param
的 param-name
。如果您使用 Java 配置 (ResourceConfig
),则应调用 property(ServerProperties.SOME_CONF, value)
。
jakarta.ws.rs.Application
设置为param-name
! - Franz Deschler