¿Qué es exactamente la clase ResourceConfig en Jersey 2?
jax-rs jersey-2.0 (1)
El estándar JAX-RS utiliza una
Application
como su clase de configuración.
ResourceConfig
extiende la
Application
.
Hay tres formas diferentes (en un contenedor de servlet) para configurar Jersey (JAX-RS):
- Con solo web.xml
-
Con web.xml
y
una clase
Application/ResourceConfig
-
Con solo una clase
Application/ResourceConfig
anotada con@ApplicationPath
.
Con solo web.xml
Es posible configurar la aplicación de manera estándar JAX-RS, pero lo siguiente es específico de 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>
Dado que Jersey se ejecuta en un contenedor de servlets, es correcto que la aplicación Jersey se ejecute como un servlet.
El Servlet Jersey que maneja las solicitudes entrantes es el
ServletContainer
.
Así que aquí lo declaramos como
<servlet-class>
.
También configuramos un
<init-param>
dice a Jersey qué paquete (s) analizar para nuestras clases
@Path
y
@Provider
para que pueda registrarlas.
Bajo el capó, Jersey creará una instancia de
ResourceConfig
, ya que eso es lo que usa para configurar la aplicación.
Luego registrará todas las clases que descubre a través del escaneo de paquetes.
Con web.xml y
Application/ResourceConfig
Si queremos configurar mediante programación nuestra aplicación con una subclase
Application
o
ResourceConfig
, podemos hacerlo con un cambio en el web.xml anterior.
En lugar de configurar un init-param para buscar paquetes, usamos un init-param para declarar nuestra subclase
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");
}
}
Aquí, configuramos la aplicación
init-param
javax.ws.rs.Application
con el nombre completo de nuestra subclase
ResourceConfig
.
Y en lugar de usar el
init-param
que le dice a Jersey qué paquete (s) escanear, solo usamos los
packages()
métodos de conveniencia
packages()
ResourceConfig
.
También podríamos usar los métodos
register()
y
property()
para registrar recursos y proveedores, y para configurar las propiedades de Jersey.
Con el método
property()
, todo lo que se puede configurar como
init-param
, también se puede configurar utilizando el método
property()
.
Por ejemplo, en lugar de llamar a los
packages()
, podríamos hacer
public JerseyApplication() {
property("jersey.config.server.provider.packages",
"com.mypackage.to.scan");
}
Con solo
Application/ResourceConfig
Sin un web.xml, Jersey necesita una forma de proporcionar el mapeo de servlets.
Hacemos esto con la anotación
@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");
}
}
Aquí con
@ApplicationPath
, es como si configuramos la asignación de servlet en web.xml
<servlet-mapping>
<servlet-name>JerseyApplication</servlet-name>
<url-pattern>/services/*</url-pattern>
</servlet-mapping>
Cuando se usa solo el código Java para la configuración, Jersey necesita encontrar alguna forma de descubrir nuestra clase de configuración.
Esto se hace con el uso de un
ServletContanerInitializer
.
Esto es algo que se introdujo en la especificación Servlet 3.0, por lo que no podemos usar la configuración "solo Java" en los contenedores de servlets anteriores.
Básicamente, lo que sucede es que el implementador del inicializador puede decirle al contenedor del servlet qué clases buscar, y el contenedor del servlet pasará esas clases al método
onStartup()
del inicializador.
En la implementación de Jersey del inicializador, Jersey lo configura para buscar clases de
Application
y clases anotadas con
@ApplicationPath
.
Ver
esta publicación
para más explicaciones.
Entonces, cuando el contenedor de servlet inicia la aplicación, el inicializador de Jersey pasará nuestra clase
Application/ResourceConfig
.
¿Qué cosas puedo hacer dentro de la subclase de ResourceConfig?
Solo mira el
ResourceConfig
.
Es sobre todo solo el registro de clases.
No hay mucho más que tengas que ver con eso.
Los principales métodos que utilizará son los métodos
register()
,
packages()
y
property()
.
El método
register()
permite registrar manualmente clases e instancias de recursos y proveedores de forma manual.
El método de
packages()
, discutido anteriormente, enumera los paquetes que desea que Jersey
@Path
@Provider
clases
@Path
y
@Provider
y las registre por usted.
Y el método
property()
permite establecer algunas
propiedades configurables
1
.
ResourceConfig
es solo una clase de conveniencia.
Recuerde, extiende la
Application
, por lo que incluso podríamos usar la clase de
Application
estándar
@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;
}
}
Con un
ResourceConfig
, simplemente haríamos
public class JerseyApplication extends ResourceConfig {
public JerseyApplication() {
register(MyResource.class);
register(new MyProvider());
packages("com.mypackages.to.scan");
}
}
Además de ser más conveniente, también hay algunas cosas que ayudan a Jersey a configurar la aplicación.
Un entorno SE
Todos los ejemplos anteriores suponen que está ejecutando en un entorno de servidor instalado, por ejemplo, Tomcat.
Pero también puede ejecutar la aplicación en un entorno SE, donde ejecuta un servidor incorporado e inicia la aplicación desde un método
main
.
A veces verá estos ejemplos cuando busque información, así que quiero mostrar cómo se ve, para que cuando se encuentre con esto, no se sorprenda y sepa cómo difiere de su configuración.
Así que a veces verás un ejemplo como
ResourceConfig config = new ResourceConfig();
config.packages("com.my.package");
config.register(SomeFeature.class);
config.property(SOME_PROP, someValue);
Lo que es más probable que ocurra aquí es que el ejemplo está usando un servidor incorporado, como Grizzly. El resto del código para iniciar el servidor podría ser algo así como
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();
}
Entonces, en este ejemplo, se está iniciando un servidor independiente y se utiliza
ResourceConfig
para configurar Jersey.
Lo diferente aquí y de los ejemplos anteriores es que en este ejemplo, no estamos extendiendo
ResourceConfig
, sino que solo lo instanciamos.
No sería diferente si tuviéramos que hacer
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());
Digamos que estaba pasando por un tutorial, y mostró una configuración para una aplicación independiente, donde crean una instancia de
ResourceConfig
, pero está ejecutando su aplicación en un contenedor de servlet y ha estado utilizando la configuración anterior donde está extendiendo
ResourceConfig
.
Bueno, ahora sabes cuál es la diferencia y qué cambios necesitas hacer.
He visto a personas hacer cosas realmente raras porque no entendieron esta diferencia.
Por ejemplo, vi a alguien instanciando un
ResourceConfig
dentro de una clase de recurso.
Por eso agregué esta pequeña pieza extra;
para que no cometas el mismo error.
Notas al pie
1. Hay varias propiedades configurables diferentes.
El enlace a
ServerProperties
son solo algunas propiedades generales.
También hay diferentes propiedades relacionadas con características específicas.
La documentación debe mencionar estas propiedades en la sección de los documentos relacionados con esa característica.
Para obtener una lista completa de
todas las
propiedades configurables, puede ver todas las
constantes de Jersey
y buscar aquellas donde el valor de la cadena comienza con
jersey.config
.
Si está usando un web.xml, entonces usaría el valor de cadena como
init-param
param-name
.
Si está utilizando la configuración de Java (
ResourceConfig
), llamaría a la
property(ServerProperties.SOME_CONF, value)
He visto muchos tutoriales de Jersey que comienzan con algo como
@ApplicationPath("services")
public class JerseyApplication extends ResourceConfig {
public JerseyApplication() {
packages("com.abc.jersey.services");
}
}
sin explicar qué es exactamente la clase
ResourceConfig
.
Entonces, ¿dónde puedo encontrar su documentación, uso, etc.?
Buscar en Google "jersey resourceconfig" no produce ningún documento oficial.
Algunas de mis preguntas sobre esta clase y su uso son:
-
¿Qué cosas puedo hacer dentro de la subclase de
ResourceConfig
? -
¿Debo registrar la subclase de
ResourceConfig
algún lugar para que se pueda encontrar o Jersey lo detecta automáticamente? -
Si la subclase se detecta automáticamente, ¿qué sucede si tengo varias subclases de
ResourceConfig
? -
¿El propósito de
ResourceConfig
el mismo que el archivoweb.xml
? Si es así, ¿qué sucede si tengo ambos en mi proyecto? ¿Uno de ellos tiene prioridad sobre el otro?