Mon besoin initial consistait à calculer le temps d'exécution des servlets CXF pour des webservices.

L'astuce consiste à créer un filtre de servlet. Mais les filtres sont aussi gérés par le conteneur me direz-vous?! Oui mais il est possible de raccrocher ces filtres au contexte spring de 2 façons :

La première solution

consiste à raccrocher le filtre au contexte spring lors de l'initialisation du filtre :

public class SpringAwareFilter implements Filter {
@Autowire MyBean myBean;
public void destroy(...) { ... }
public void doFilter(...) { ....
myBean.methodeToIntercept(...);
....
} public void init(FilterConfig filterConfig) throws ServletException { ServletContext servletContext = filterConfig.getServletContext(); WebApplicationContext webApplicationContext = WebApplicationContextUtils.getWebApplicationContext(servletContext); AutowireCapableBeanFactory autowireCapableBeanFactory = webApplicationContext.getAutowireCapableBeanFactory(); autowireCapableBeanFactory.configureBean(this, "myBean");
}

Une fois le filtre accroché au contexte Spring, il est possible d'ajouter le pointcut  sur methodToIntercept du bean Spring myBean.

Source : http://forum.springsource.org/showthread.php?t=60983

La deuxième solution

est d'utiliser directement la classe Spring DelegatingFilterProxy qui fait sensiblement la même chose.

On crée d'abord un filtre en implémentant Filter de la façon suivante :

package fr.openfarm.aop;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;


public class ServletPointcutFilter implements Filter {

@Override
public void destroy() {
// cette partie "lifecycle" du filtre est normalement prise en charge
// par la classe org.springframework.web.filter.DelegatingFilterProxy
// déclarée dans le web.xml
}

@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
// filtre identité que ne à rien d'autre que donner la main
// au filtre de servlet suivant
// c'est cette méthode publique qui va pouvoir être interceptée
// et donc utilisée comme pointcut par Spring AOP
chain.doFilter(request, response);
}

@Override
public void init(FilterConfig filterConfig) throws ServletException {
// cette partie "lifecycle" du filtre est normalement prise en charge
// par la classe org.springframework.web.filter.DelegatingFilterProxy
// déclarée dans le web.xml
}

}

Ensuite, il faut déclarer ce filtre comme un bean spring :

<bean id="servletPointcutFilter" class="fr.openfarm.aop.ServletPointcutFilter"/>


Visible du contexte Spring, il peut alors être candidat aux advices.

Il faut ensuite déclarer le filtre DelegatingFilterProxy de Spring et son application dans le fichier web.xml :

<?xml version="1.0" encoding="UTF-8"?>

<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
version="2.4">

<display-name>CXF WS-S</display-name>

<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:applicationContext.xml
</param-value>
</context-param>

<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<!-- Il est impossible d'intercepter les servlets par Spring AOP
car elles sont hors contexte spring
l'astuce consiste à appliquer un filtre de servlet sur les CXF Servlets
grâce au filtre DelegatingFilterProxy qui s'enregistre dans le contexte spring
et qui déléguera au filtre déclaré comme bean servletPointcutFilter
-->
<filter>
<filter-name>servletPointcutFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>

<filter-mapping>
<filter-name>servletPointcutFilter</filter-name>
<servlet-name>CXFServlet</servlet-name>
</filter-mapping>

<servlet>
<servlet-name>CXFServlet</servlet-name>
<display-name>CXF Servlet</display-name>
<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>CXFServlet</servlet-name>
<url-pattern>/services/*</url-pattern>
</servlet-mapping>

<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>

</web-app>

Toujours fidèle à la devise "convention over configuration", il faut utiliser comme valeur de <filter-name> dans le fichier web.xml l'identifiant du bean déclaré dans Spring. Le DelegatingFilterProxy s'enregistre auprès du context Spring et fera office de Filtre proxy en appelant notre servletPointcutFilter.

Le filtre de servlet d'exécutant systématiquement avec les servlets, on a donc un moyen de s'insérer dans le fil d'exécution, à défaut d'être au plus près de la servlet. Comme dans la première méthode, on peut alors appliquer un advice sur le filtre de servlet avec par exemple l'advice @Around et le pointcut suivant :

@Aspect
public class TimeLoggerAspect {

@Pointcut("execution(public void fr.openfarm.aop.ServletPointcutFilter.doFilter(..))")
public void servlet() {}

@Around("servlet()")
public void logTimeExec() { ... }

}

Source :

http://forum.springsource.org/showthread.php?t=58083

Sinon un très bon article sur AOP AOP : mythes et réalités ( http://www.ibm.com/developerworks/java/library/j-aopwork15/ )