jersey jax-rs jersey-2.0

¿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):

  1. Con solo web.xml
  2. Con web.xml y una clase Application/ResourceConfig
  3. 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 archivo web.xml ? Si es así, ¿qué sucede si tengo ambos en mi proyecto? ¿Uno de ellos tiene prioridad sobre el otro?