07-11-2006 Raul Vicente
Hace poco leí un artículo sobre cómo realizar aspectos de manera declarativa en Spring 2.0 utilizando AspectJ. He mencionado el tema en los post Spring2.0 manejo declarativo de transacciones y Spring2.0 Annotations, pero hasta ahora no había tenido tiempo para dejarlo patente en el blog.
Spring 2.0 se integra perfectamente con AspectJ permitiendo definir aspectos en AspectJ de manera declarativa, a su vez también da la posibilidad de utilizar annotations para definir los aspectos y de esa manera poder librarnos del XML, pero esto acarrea consecuencias y en este caso utilizar las annotations supone ligar la aplicación al container de Spring, así pues, se aconseja utilizar annotations para desarrollar prototipos pero no para el proyecto final ya que se aconseja que la aplicación esté lo más desacoplada que se pueda con lo que la mejor opción es el XML.
Vamos a demostrar como siempre el movimiento andando, supongamos que se dispone de esta clase:
public class MockService{
public PedidoVO getPedido(String id) {
PedidoVO pedido = new PedidoVO();
pedido.setId(id);
pedido.setName(“MockPedido”);
return pedido;
}
}
Ahora vamos a programar tres aspectos para el método getPedido, uno que se ejecute antes de llamar al método, otro que se ejecute después y otro que envuelva la llamada del método. Los tres típicos ejemplos de programación orientada a aspectos, antes en Spring 1.x los aspectos tenían que implementar la interfaz MethodInterceptor pero ahora en Spring 2.0 no hace falta los aspectos son pojos normales y corrientes.
Así pues, la implementación de los aspectos quedaría así:
public class PojoBeforeAspect {
public static Logger logger = Logger.getLogger(PojoBeforeAspect.class);
public void log(String idPedido) {
logger.info(“Se pide el pedido ” + idPedido);
}
}
public class PojoAfterAspect {
public static Logger logger = Logger.getLogger(PojoAfterAspect.class);
public void logResult(JoinPoint jp, PedidoVO pedido) {
logger.info(“Llamando a ” + jp.getSignature() + ” resultado: ” + pedido.getName());
}
}
public class PojoAroundAspect {
public static Logger logger = Logger.getLogger(PojoAroundAspect.class);
public PedidoVO aroundMethod(ProceedingJoinPoint pjp, String id) throws Throwable {
logger.info(“Llamando a ” + pjp.getSignature());
Object result = pjp.proceed();
return (PedidoVO) result;
}
}
El único código que tiene algo de enjundia es el último que intercepta la llamada getPedido() hace un login de que se ha pasado por el método y lo deja continuar, esto no es muy útil pero es un ejemplo de iniciación lo realmente útil sería capturar el método de creación de un botón en una aplicación Swing por ejemplo y en función de si se tiene permiso para ejecutar una acción hacer el pjp.proceed() o no, de esa manera sólo se mostraría el botón cuando se esté autorizado.
Ahora vamos con el tratamiento del XML:
Por supuesto lo primero sería dar de alta en el contexto de Spring los beans que conforman los tres aspectos y nuestra clase a la que le vamos a aplicar el aspecto:
< bean id="mockService"
class=”org.dahernan.service.MockService”/ >
< bean id="pojoBeforeAspect"
class=”org.dahernan.aspects.PojoBeforeAspect”/>
< bean id="pojoAfterAspect"
class=”org.dahernan.aspects.PojoAfterAspect”/>
< bean id="pojoAroundAspect"
class=”org.dahernan.aspects.PojoAroundAspect”/>
Y ahora cómo se deben aplicar esos aspectos:
< aop:aspect id="beforeAspect" ref="pojoBeforeAspect" >
< aop:advice
pointcut=”execution(* org.dahernan..*MockService.getPedido(..)) and args(idPedido)”
method=”log”
kind=”before”
/ >
< /aop:aspect>
Se define una referencia al id de la clase que contiene el aspecto y dentro del aspecto se define el pointcut dónde ha de aplicarse el aspecto, el tipo del aspecto y el método de la clase que hay que ejectuar cuando se ejecute el aspecto.
El aspecto a ejecutar después del método sería este:
< aop:aspect id="afterAspect" ref="pojoAfterAspect" >
< aop:advice
pointcut=”execution(* org.dahernan..*MockService.getPedido(..))”
returning=”pedido”
method=”logResult”
kind=”afterReturning”
/ >
< /aop:aspect>
Como se puede observar, este ejemplo es muy similar al ejemplo anterior sólo destacar que el tipo es afterReturning, es decir, que se ejecuta despés de que el método devuelva un resultado para diferenciarlo de afterThrowing que sirve para aplicar un aspecto cuando se eleva una excepción.
El código del último aspecto sería el siguiente:
< aop:aspect id="aroundAspect" ref="pojoAroundAspect" >
< aop:advice
pointcut=”execution(* org.dahernan..*MockService.getPedido(..)) and args(id)”
method=”aroundMethod”
kind=”around”
/ >
< /aop:aspect>
El aspecto es muy similar a los anteriores ahora vamos a ver cómo quedaría nuestros aspectos si hubíeramos utilizado annotations:
@Aspect
public class PojoBeforeAspect {
public static Logger logger = Logger.getLogger(PojoBeforeAspect.class);
@Before(
pointcut=”execution(* org.dahernan..*MockService.getPedido(..)) and args(idPedido)”)
public void log(String idPedido) {
logger.info(“Se pide el pedido ” + idPedido);
}
}
@Aspect
public class PojoAfterAspect {
public static Logger logger = Logger.getLogger(PojoAfterAspect.class);
@AfterReturning(
pointcut=execution(* org.dahernan..*MockService.getPedido(..))”
returning=”pedido”)
public void logResult(JoinPoint jp, PedidoVO pedido) {
logger.info(“Llamando a ” + jp.getSignature() + ” resultado: ” + pedido.getName());
}
}
@Aspect
public class PojoAroundAspect {
public static Logger logger = Logger.getLogger(PojoAroundAspect.class);
@Around(
pointcut=”execution(* org.dahernan..*MockService.getPedido(..)) and args(id)”)
public PedidoVO aroundMethod(ProceedingJoinPoint pjp, String id) throws Throwable {
logger.info(“Llamando a ” + pjp.getSignature());
Object result = pjp.proceed();
return (PedidoVO) result;
}
}
El código es muy intuitivo y habiendo entendido la parte de cómo configurar el XML sólo es poner lo mismo en las clases que conforman nuestros aspectos, tan sólo falta habilitar la annotations en el applicationContext.xml y eliminar el código de los aspectos del XML.
< aop:aspectj-autoproxy/>
Para los interesados en el tema os dejo la dirección del artículo original y la dirección de la págnia donde se encuentra la documentación on-line de Spring, en concreto el tema de los aspectos se aborda en el capítulo 6.
1. sassser | julio 9th, 2007 at 1:38 pm
Muy bueno el articulo. Realmente es muy util para poder apreciar ‘insitu’ las catacteristicas que presenta la AOP. Solo quiero remarcar una cosilla, no consigo resolver donde se encuantran las classes como JointPoint o ProceedingJoinPoint, quizas me he despistado pero no logro encontrarlas.
Gracias y un saludo
2. Raúl Vicente | julio 10th, 2007 at 9:19 am
Buenas sasser, no te preocupes por esas clases, Spring se encarga de que esos objetos estén disponibles cuando se llama al método, vamos que su implementación está dentro de Spring. Simplemente se ofrece el JoinPoint al usuario por si a través de él tiene que acceder a alguna información, pero no hay que programarla.
Un saludo y gracias.
3. Cesar Morales Rosas | septiembre 4th, 2007 at 11:53 pm
hola alguien que me pueda explicar esta tecnologia de spring lo que pasa es que no entiendo muy bien todabia a fondo lo que es spring y tambien si alguien sabe sobre un ejemplo con mucho gusto se lo agrade sere
4. Hernan | septiembre 3rd, 2008 at 5:16 pm
Muy bueno, explica en concreto la AOP, vengo de Struts y estoy comenzando con Spring y me esta sorprendiendo la potencia que tiene el framework, bueno te comento que estoy siguiendo Professional Java Development with the Spring Framework si lo has leido comentame algo…saludos mil
5. Raul | septiembre 3rd, 2008 at 8:33 pm
Buenas Hernan,
no he leído ese libro en concreto leí el Profession Devolopment without EJB, que me pareció demasiado duro para empezar y termine con el Spring in Action de Manning, que me pareció un gran ligro, de todas maneras le echaré un vistazo a lo mejor es una buena referencia y se la puedo aconsejar a algún amigo.
Muchas gracias por colaborar.