Ciclo de Vida

Lo más habitual es que un servidor web mantenga una única instancia de un servlet concreto. O uno por cada máquina virtual en entornos distribuidos.

Cuando llega una petición, el servidor resuelve que servlet concreto tiene que atenderla, y si la instancia de dicho servlet no existe entonces la crea. No obstante, se puede forzar a que se instancie un determinado servlet al desplegar la aplicación utilizando la etiqueta load-on-startup en el fichero web.xml:

<servlet>
  <servlet-name>HelloServlet</servlet-name>
  <servlet-class>com.company.servlet.HelloServlet</servlet-class>
  <load-on-startup>1</load-on-startup>
</servlet>

El valor numérico de la etiqueta indica el orden en que tiene que instanciarse. Un valor negativo indica que no tiene que instanciarse automáticamente al realizar el despliegue.

El ciclo de vida de un servlet está definido por la interface javax.servlet.Servlet que todos los servlets implementan. Cuando se crea una instancia se llama al método init para dar la oportunidad a que se inicialice. Cuando se recibe una petición que tiene que atender se llama al método service para que la atienda. Y cuando se va a destruir la instancia se llama al método destroy para que pueda terminar en orden.

public class HelloServlet extends HttpServlet {

    @Override
    public void init() {
    ...

    @Override
    public void destroy() {
    ...

El método init tiene otra forma en la que recibe un parámetro de tipo ServletConfig con detalles de la configuración del entorno de ejecución. Un servlet puede decidir que no debe instanciarse por código dentro del método init elevando una excepción de tipo ServletException o UnavailableException. Aunque el servidor web puede tratar de instanciarlo de nuevo más adelante. En el caso de UnavailableException se permite indicar un tiempo (en segundos) durante el cual no se debe intentar volver a instanciar.

El método service no se suele sobrecargar cuando se hereda de HttpServlet, ya que la clase base lo que hace es analizar la petición y llamar a los métodos doGet, doPost, …

El tiempo que está instanciado en memoria un servlet es responsabilidad del servidor web, que puede decidir mantenerlo unos pocos milisegundos, o durante todo el tiempo que esté la aplicación desplegada.

Un mismo servlet puede ser invocado de forma concurrente por varias peticiones simultáneas, por lo que el código debe ser seguro en ese aspecto, evitando el uso de variables de instancia y sincronizando el acceso a recursos si es necesario. El uso de synchronized sobre los métodos está desaconsejado, ya que impide la ejecución en paralelo obligando a serializar las llamadas.

Dispatchers

Dentro de una aplicación web a veces es necesario tener que redirigir el flujo de proceso de un servlet a otro, o tener que añadir al resultado dinámico generado por un servlet el generado por otro. Los dispatchers son las clases que permiten realizar este tipo de tareas.

A los dispatchers se accede a través de dos métodos de Servlet Context. El método getRequestDispatcher devuelve un objeto de tipo RequestDispatcher correspondiente a un path dado, que necesariamente tiene que empezar con el caracter separador «/». El método getNamedDispatcher devuelve un objeto de tipo RequestDispatcher correspondiente a un nombre de servlet dado.

...
RequestDispatcher dispatcher = context.getRequestDispatcher("/otra/url");
...

Una vez obtenida una instancia del dispatcher se puede llamar a sus métodos. El método forward redirige el flujo de proceso, aunque es necesario que se llame antes de haber enviado ninguna información al cliente y con el buffer de respuesta limpio. El método include permite que se añada información al buffer de respuesta, aunque en ese caso el uso del objeto respuesta es limitado, no pudiéndose añadir cabeceras HTTP por ejemplo.

...
dispatcher.forward(request, response);
...