Ultimamente tornou-se muito importante sabermos como podemos manipular os Servlet Filters e Event Listeners para aplicações mais complexas e que precisam de tais funcionalidades. Ambos são muito utilizados nas aplicações comerciais e suportam diversas funcionalidades vitais para aplicações conforme veremos no restante do artigo.

Nas próximas seções veremos o que são e como podemos utilizar os Servlet Filter e Event Listeners. Também veremos como podemos defini-los, as novidades incorporadas nas duas funcionalidades e códigos de exemplo para demonstrar como podemos utilizá-los.

Servlet Filters

Um Servlet Filter pode ser utilizado para diversas situações. Com Servlet Filter podemos atualizar a solicitação (request) e a resposta (response) dos objetos, além manipular informações como do cabeçalho de e para o Servlet. Vale ressaltar que os filtros não criam a resposta, eles apenas modificam ou adaptam as solicitações e as respostas. Outras tarefas típicas dos filtros são: autenticação, logging, compressão de dados, encriptação de dados, entre outras.

Os filtros são empacotados juntamente com um Servlet e agem sobre o conteúdo dinâmico ou estático.

Para definirmos um filtro usamos a anotação @WebFilter conforme exemplo da Listagem 1.

Listagem 1. Exemplo como podemos definir um filtro através de uma anotação WebFilter.


  @WebFilter("/*")
  public class LoggingFiltro implements javax.servlet.Filter {
   
           public void doFilter(HttpServletRequest request, HttpServletResponse response) {
                     //. . .
           }
  }
  

No código acima, o “LoggingFiltro” é um filtro aplicado a todos os Servlets e página de conteúdos estáticos na aplicação web. Ou seja, para toda requisição teremos esse filtro sendo processado. Como podemos ver esse filtro tem acesso à solicitação e a resposta proveniente dessa solicitação.

A anotação @WebInitParam pode ser utilizada para especificar parâmetros de inicialização para os filtros.

Um filtro e o Servlet destino sempre executam no mesmo segmento de chamada. Vários filtros podem ser organizados em uma cadeia de filtros.

Podemos também definir um filtro usando os elementos e no deployment descriptor web.xml. Segue na Listagem 2 um exemplo.

Listagem 2. Exemplo de como podemos definir um filtro da maneira antiga utilizando um arquivo web.xml.


  <filter>
           <filter-name>LoggingFilter</filter-name>
           <filter-class>org.sample.LoggingFilter</filter-class>
  </filter>
   
  . . .
   
  <filter-mapping>
           <filter-name>LoggingFilter</filter-name>
           <url-pattern>/*</url-pattern>
  </filter-mapping>
  

Além de declararmos os filtros usando @WebFilter e web.xml, podemos defini-los programaticamente usando métodos “ServletContext.addFilter”. Podemos fazer isto através do método “ServletContainerInitializer.onStartup” ou do método “ServletContextListener.contextInitialized”.

O método “addFilter” retorna um “ServletRegistration.Dynamic”, que pode então ser utilizado para adicionar o mapeamento para padrões de URL, configurar parâmetros de inicialização, e lidar com outros itens de configuração.

Segue na Listagem 3 um exemplo de como poderíamos definir um filtro programaticamente.

Listagem 3. Exemplo de como podemos definir um filtro programaticamente.


  public class MeuInicializador implements ServletContainerInitializer {
           public void onStartup (Set<Class<?>> clazz, ServletContext context) {
                     FilterRegistration.Dynamic reg =
                              context.addFilter("LoggingFiltro", "com.exemplo.LoggingFiltro");
                     reg.addMappingForUrlPatterns(null, false, "/");
           }
  }
  

Event Listeners

Os Event Listeners fornecem eventos de retorno de chamada do ciclo de vida para objetos “ServletContext”, “HttpSession”, e “ServletRequest”. Esses listeners são classes que implementam uma interface que suporta notificações de evento para alterações de estado nesses objetos.

Cada classe é anotada com @WebListener, declarado no web.xml, ou registrado via um dos métodos “ServletContext.addListener”.

Pode haver múltiplas classes listener "monitorando" cada tipo de evento, e eles podem ser especificados na ordem em que o container invoca os listeners para cada tipo de evento. Os listeners são notificados na ordem inversa durante o encerramento do aplicativo. Listeners em contexto de Servlets monitoram eventos a partir de recursos nesse contexto. Veja a Listagem 4.

Listagem 4. Exemplo de implementação de um listener.


  @WebListener
  public class MeuContextListener implements ServletContextListener {
           @Override
           public void contextInitialized(ServletContextEvent sce) {
                     ServletContext context = sce.getServletContext();
   
                     //. . .
   
           }
   
           @Override
           public void contextDestroyed(ServletContextEvent sce) {
                     //. . .
           }
  }
  

O ServletContextAttributeListener é usado para monitorar alterações de atributos no contexto.

Segue o código de exemplo na Listagem 5.

Listagem 5. Exemplo de um listener para monitorar alterações de atributos no contexto.


  public class MeuServletContextAttributeListener implements ServletContextAttributeListener {
           @Override
           public void attributeAdded(ServletContextAttributeEvent event) {
                     //. . . event.getName();
                     //. . . event.getValue();
           }
   
           @Override
           public void attributeRemoved(ServletContextAttributeEvent event) {
                     //. . .
           }
   
           @Override
           public void attributeReplaced(ServletContextAttributeEvent event) {
                     //. . .
           }
  }
  

O HttpSessionListener monitora eventos a partir de recursos nessa sessão (Listagem 6).

Listagem 6. Exemplo de um listener para monitorar eventos na sessão.


  @WebListener
  public class MeuSessionListener implements HttpSessionListener {
           @Override
           public void sessionCreated(HttpSessionEvent hse) {
                     HttpSession session = hse.getSession();
                     
                     //. . .
   
           }
   
           @Override
           public void sessionDestroyed(HttpSessionEvent hse) {
   
                     //. . .
   
           }
  }
  

O HttpSessionActivationListener é usado para monitorar por eventos quando a sessão é passivada (serialização da sessão) ou ativada. Veja a Listagem 7.

Listagem 7. Exemplo de listener para monitorar quando a sessão é passivada ou ativada.


  public class MeuHttpSessionActivationListener implements HttpSessionActivationListener {
   
           @Override
           public void sessionWillPassivate(HttpSessionEvent hse) {
                     // ... hse.getSession();
           }
   
           @Override
           public void sessionDidActivate(HttpSessionEvent hse) {
                     // ...
           }
  }
  

O HttpSessionAttributeListener é utilizado para monitorar alterações de atributos na sessão, conforme a Listagem 8.

Listagem 8. Exemplo de listener para monitorar alterações de atributos na sessão.


  public class MeuHttpSessionAttributeListener implements HttpSessionAttributeListener {
           @Override
           public void attributeAdded(HttpSessionBindingEvent event) {
                     HttpSession session = event.getSession();
                     //. . . event.getName();
                     //. . . event.getValue();
           }
   
           @Override
           public void attributeRemoved(HttpSessionBindingEvent event) {
                     //. . .
           }
   
           @Override
           public void attributeReplaced(HttpSessionBindingEvent event) {
                     //. . .
           }
  }
  

O HttpSessionBindingListener é utilizado para monitorar eventos quando um objeto é ligado ou desligado de uma sessão. Veja um exemplo na Listagem 9.

Listagem 9. Exemplo utilizando listener para monitorar quando um objeto é ligado ou desligado de uma sessão.


  public class MeuHttpSessionBindingListener implements HttpSessionBindingListener {
           @Override
           public void valueBound(HttpSessionBindingEvent event) {
                     HttpSession session = event.getSession();
                     //. . . event.getName();
                     //. . . event.getValue();
           }
   
           @Override
           public void valueUnbound(HttpSessionBindingEvent event) {
                     //. . .
           }
  }
  

O ServletRequestListener monitora eventos de recursos nessa solicitação (request), conforme a Listagem 10.

Listagem 10. Exemplo de listener para monitorar eventos de recursos na solicitação.


  @WebListener
  public class MeuRequestListener implements ServletRequestListener {
           @Override
           public void requestDestroyed(ServletRequestEvent sre) {
                     ServletRequest request = sre.getServletRequest();
                     //. . .
           }
   
           @Override
           public void requestInitialized(ServletRequestEvent sre) {
                     //. . .
           }
  }
  

O ServletRequestAttributeListener é utilizado para monitorar alterações de atributos na solicitação (request).

Temos também o “AsyncListener”, que é utilizado para gerenciar eventos assíncronos tais como concluído, tempo limite excedido, ou um erro.

Além de declarar listeners usando @WebListener e web.xml, podemos defini-los programaticamente usando métodos “ServletContext.addListener”. Podemos definir isto através do método “ServletContainerInitializer.onStartup” ou “ServletContextListener.contextInitialized” conforme já foi falado anteriormente no artigo.

O método ServletContainerInitializer.onStartup é invocado quando a aplicação está iniciando para um dado ServletContext. Segue um exemplo na Listagem 11.

Listagem 11. Exemplo de como definir um listener programaticamente.


  public class MeuInicializador implements ServletContainerInitializer {
           public void onStartup(Set<Class<?>> clazz, ServletContext context) {
                     context.addListener("com.exemplo.MeuContextListener");
           }
  }
  

Bibliografia

  1. Josh Juneau. Java EE 7 Recipes: A Problem-Solution Approach. Apress, 2013.
  2. Josh Juneau. Introducing Java EE 7: A Look at What's New. Apress, 2013.
  3. Arun Gupta. Java EE 7 Essentials. O'Reilly, 2013.