java - DinĂ¡micamente(un) despliegue de recursos en Jersey
jersey-2.0 (2)
Necesito desplegar y desplegar recursos en un ServletContainer de Jersey.
Parece que no hay manera de "anular el registro" de los recursos en un ResourceConfig, por lo que la ruta que estoy siguiendo es reemplazar todos los recursos con un nuevo conjunto.
Aunque la documentación dice que registerResources en ResourceConfig reemplaza todos los recursos, la navegación a través del código fuente parece contradecir esto.
La solución que encontré fue recargar el ServletContainer con un ResourceConfig completamente nuevo.
Set<Class<?>> classes = ...
ResourceConfig config = new ResourceConfig(classes);
container.reload(config);
Esto funciona bien hasta que despliegue un recurso que da como resultado una excepción ModelValidationException. Después de eso no puedo recuperar el ServletContainer en un estado adecuado.
Si miro el código fuente:
public void reload(final ResourceConfig configuration) {
try {
containerListener.onShutdown(this);
webComponent = new WebComponent(webComponent.webConfig, configuration);
containerListener = webComponent.appHandler;
containerListener.onReload(this);
containerListener.onStartup(this);
} catch (final ServletException ex) {
LOGGER.log(Level.SEVERE, "Reload failed", ex);
}
}
La excepción ModelValidationException se genera desde el constructor WebComponent. Después de eso, cualquier llamada para recargar resulta en una excepción del método onShutdown, causado por checkState en el método preDestroy del ServiceLocatorImpl.
Puedo evitar la excepción ignorando los errores de validación
ResourceConfig config = new ResourceConfig(classes);
config.property(ServerProperties.RESOURCE_VALIDATION_IGNORE_ERRORS,
Boolean.TRUE);
container.reload(config);
Sin embargo, ahora no hay forma de averiguar si hubo algún error, sino de explorar el registro, lo cual es realmente malo.
Según el comentario de Heenenee, he intentado subclasificar ServletContainer, pero algo como esto da problemas porque el ResourceConfig no se puede colocar en dos componentes web.
Intenté crear el componente web antes de apagarlo para obtener una salida anticipada, pero esto falla la recarga real si no hay un error en los recursos (porque no se puede modificar el resourceconfig después de haber creado el componente web)
@Override
public void reload(ResourceConfig configuration) {
try {
new WebComponent(new WebServletConfig(this), configuration);
} catch (ServletException e) {
LOGGER.log(Level.SEVERE, "Reload failed", e);
List<ResourceModelIssue> resources = Collections.emptyList();
throw new ModelValidationException(e.getMessage(), resources);
}
super.reload(configuration);
}
¿Hay otra forma de desplegar en caliente los recursos? ¿Hay alguna manera de restablecer el ServletContainer después de una recarga fallida?
Jersey no es técnicamente un contenedor de servlets, es un marco REST / JaxB que se ejecuta en un contenedor de servlets.
La mayoría de los contenedores de servlets incrustables, Tomcat, Jetty, Grizzly le permite volver a implementar aplicaciones y servlets en tiempo de ejecución. Pero la redistribución no suele ser una característica que utiliza cuando incrusta el contenedor en el código.
La redistribución en caliente es más útil en la producción, ya que le permite implementar continuamente nuevas versiones. En Tomcat, puede tener una versión nueva y antigua de una aplicación implementada en el mismo servidor, y tomcat garantiza que las nuevas sesiones se inicien en la versión más nueva de la aplicación, pero las versiones anteriores continuarán usando la versión de la aplicación con la que se iniciaron. Cuando una aplicación no se utiliza, el registrador no se implementa automáticamente.
No creo que esto pueda lograrse sin el uso de un contenedor de servlets que admita implementaciones en caliente. En mi experiencia, una buena manera de hacerlo es usar un contenedor que admita OSGi. Puedes echar un vistazo a Eclipse Virgo o Apache Karaf .
Por ejemplo, en un entorno OSGi, puede crear módulos (llamados paquetes) que se pueden soltar en una carpeta escaneada para habilitar funciones en tiempo de ejecución, o eliminarlas de una carpeta, para deshabilitar algunas funciones. Esto es similar a cómo funcionan los complementos en Eclipse IDE, donde la instalación / desinstalación de un nuevo complemento no necesariamente requiere un reinicio.