Filters

Los filtros pueden verse como un tipo especial de servlets, en la medida que se configuran en el fichero web.xml y los invoca el servidor web. No obstante, su propósito es bastante distinto. No actúan como componentes de una aplicación que responden a una petición, sino como componentes proxy que capturan el tráfico de recursos con el propósito de auditarlo o modificarlo. En este caso el término recurso abarca tanto al contenido desplegado de forma estática como al generado dinámicamente.

Un filtro es una clase Java que implementa la interface javax.servlet.Filter:

public class HelloFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    ...

    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
    ...

    @Override
    public void destroy() {
    ...

Los filtros deben declararse en el fichero web.xml para que el servidor web sepa que tiene que instanciarlos:

<filter>
  <filter-name>HelloFilter</filter-name>
  <filter-class>com.company.filter.HelloFilter</filter-class>
</filter>

Y de forma similar a los servlets, para cada filtro debe indicarse las URLs para las que tienen que invocarse:

<filter-mapping>
  <filter-name>HelloFilter</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>

De forma alternativa a la etiqueta url-pattern, que mapea un conjunto de URLs, puede utilizarse la etiqueta servlet-name, que permite indicar el nombre de un servlet específico. De igual forma, se puede utilizar la etiqueta dispatcher para restringir la activación del filtro a una operación de forward o include. Y adicionalmente se pueden indicar parámetros de inicialización específicos para un filtro utilizando la etiqueta init-param.

El servidor web instancia todos los filtros después del despliegue y antes de atender a ninguna petición, teniendo en cuenta que en entornos distribuidos los filtros se instancian por máquina virtual, y que en cualquier caso la lista de filtros forman una cadena, de manera que la información viaja a través de todos ellos, uno detrás de otro.

El método init es llamado después de instanciar el filtro. El método destroy es llamado antes de destruir la instancia del filtro. El método doFilter es llamado por el servidor web cuando este recibe una petición que casa con su mapeo, pasándole como argumentos los objetos petición y respuesta, así como una referencia a la cadena de filtros.

Los filtros pueden crear proxies a modo de wrappers sobre los objetos petición y respuesta con el objetivo de añadirles funcionalidad o modificar su contenido. O añadir cabeceras a las respuestas:

...
chain.doFilter(request, response);

HttpServletResponse modified = (HttpServletResponse) response;

modified.addHeader("hello", "world");
...

Como se observa, es responsabilidad de un filtro llamar al siguiente de la cadena. Si no se hace se interrumpe la secuencia normal de procesamiento de la petición en curso, lo que en algunos casos puede ser conveniente, para implementar algún tipo de control de seguridad por ejemplo.

Listeners

Los listeners son componentes web que permiten a los desarrolladores monitorizar el estado de los objetos de tipo ServletContext, HttpSession y ServletRequest. Un ejemplo de uso típico es monitorizar la creación del contexto principal, que en cierta forma equivale al «arranque» de una aplicación web, con el objeto de establecer una conexión con una base de datos y guardar dicha conexión dentro del propio contexto.

Los listeners se declaran dentro del fichero web.xml de forma similar a otros componentes web, aunque requieren menos información:

<listener>
  <listener-class>com.company.listener.HelloListener</listener-class>
</listener>

Los listeners son instanciados al arrancar el servidor web y destruidos al pararlo. En entornos distribuidos se crea un listener por máquina virtual.

Un listener es una clase Java que implemente una o más de las interfaces especializadas que existen para cada uno de los tipos de objeto soportados, como por ejemplo ServletContextListener:

public class HelloListener implements ServletContextListener {

    @Override
    public void contextInitialized(ServletContextEvent sce) {
    ...

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
    ...

La interface ServletContextListener permite monitorizar el ciclo de vida de los objetos de tipo ServletContext, tanto cuando han sido creados y están listos para recibir la primera petición, como cuando están a punto de ser destruidos.

La interface ServletContextAttributeListener permite monitorizar el cambio en los atributos de los objetos de tipo ServletContext, tanto cuando han sido añadidos, modificados o borrados.

La interface HttpSessionListener permite monitorizar el ciclo de vida de los objetos de tipo HttpSession, tanto cuando han sido creados, invalidados o expirados por timeout.

La interface HttpSessionAttributeListener permite monitorizar el cambio de atributos de los objetos de tipo HttpSession, tanto cuando han sido añadidos, modificados o borrados.

La interface HttpSessionActivationListener permite monitorizar la migración de sesiones en entornos distribuidos de los objetos de tipo HttpSession. Es decir, cuando se mueven de un servidor a otro.

La interface HttpSessionBindingListener permite monitorizar el cambio de las propiedades de los objetos almacenados dentro de los objetos de tipo HttpSession, siempre y cuando implementen la interface que proporciona las facilidades de binding.

La interface ServletRequestListener permite monitorizar el ciclo de vida de los objetos de tipo ServletRequest, en particular cuando una petición está lista para ser procesada.

La interface ServletRequestAttributeListener permite monitorizar el cambio en los atributos de los objetos de tipo ServletRequest, tanto cuando han sido añadidos, modificados o borrados.