Mostrando las entradas con la etiqueta aop. Mostrar todas las entradas
Mostrando las entradas con la etiqueta aop. Mostrar todas las entradas

viernes, 5 de febrero de 2010

Creación de Aspectos con Spring e Interfaces

En los anteriores post comenté como se pueden implementar aspectos mediante anotaciones y en forma declarativa mediante xml, ahora lo vamos a hacer mediante interfaces y unas cuantas declaraciones xml. Veamos; en los aspectos declarados con el tag <aspect> la clase java era un simple javabean, en este post vamos a ver que para evitar el uso de <aspect la clase java que define el aspecto debe de implementar al menos una interface de las siguientes para que las implementaciones de la interface definan el aspecto en la clase, estas interfaces son las siguientes: MethodBeforeAdvice,AfterReturningAdvice,ThrowsAdvice, el primero de ellos me sirve si quiero que mi clase aspecte métodos antes de que estos se ejecuten, si la clase implementa AfterReturningAdvice entonces el aspecto se ejecutará al finalizar satisfactoriamente la ejecución del método aspectado y finalmente la implementación de la interface ThrowsAdvice capturará las posibles excepciones que el método aspectado lance. Los aspectos son los siguientes:

AuditoriaAspectImpl.java
package pe.com.slcsccy.aop;

import java.lang.reflect.Method;

import org.springframework.aop.AfterReturningAdvice;
import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.aop.ThrowsAdvice;

public class AuditoriaAspectImpl
implements MethodBeforeAdvice,AfterReturningAdvice,ThrowsAdvice{

/* Aspecto llamado antes de la ejecución del método que lo ejecuta.
* @param metodo: método que lanza la ejecución de este aspecto.
* @param argumentos: Listado de argumentos del método, debemos hacer el cast.
* @param instancia: Instancia que contiene el método y ejecuta el aspecto.
* */
@Override
public void before(Method metodo, Object[] argumentos, Object instancia)
throws Throwable {
System.out.println("Auditoria.before(..), metodo:"+metodo.getName()+",instancia:"+instancia.getClass().getCanonicalName());
}
/* Aspecto llamado cada vez que la ejecución del método termina con excepción.
* @param metodo: método que lanza la ejecución de este aspecto.
* @param argumentos: Listado de argumentos del método, debemos hacer el cast.
* @param instancia: Instancia que contiene el método y ejecuta el aspecto.
* @param exception: Instancia de la excepción que fué lanzada por el aspecto.
* */
public void afterThrowing(Method metodo, Object[] argumentos, Object instancia, Exception exception){
System.out.println("Auditoria.afterThrowing(..), metodo:"+metodo.getName()+",instancia:"+instancia.getClass().getCanonicalName());
}
/* Aspecto llamado cada vez que la ejecución del método termina satisfactoriamente.
* @param retorno: Instancia que retorna el método.
* @param metodo: método que lanza la ejecución de este aspecto.
* @param argumentos: Listado de argumentos del método, debemos hacer el cast.
* @param instancia: Instancia que contiene el método y ejecuta el aspecto.
* */
@Override
public void afterReturning(Object retorno, Method metodo, Object[] argumentos,
Object instancia) throws Throwable {
System.out.println("Auditoria.afterReturning(..), metodo:"+metodo.getName()+",instancia:"+instancia.getClass().getCanonicalName());
}
}


ImpresorAspectImpl.java
package pe.com.slcsccy.aop;

import java.lang.reflect.Method;

import org.springframework.aop.AfterReturningAdvice;
import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.aop.ThrowsAdvice;

public class ImpresorAspectImpl implements MethodBeforeAdvice,AfterReturningAdvice,ThrowsAdvice{

@Override
public void before(Method metodo, Object[] argumentos, Object instancia)
throws Throwable {
System.out.println("Impresor.before(..), metodo:"+metodo.getName()+",instancia:"+instancia.getClass().getCanonicalName());
}
public void afterThrowing(Method metodo, Object[] argumentos, Object instancia, Exception exception){
System.out.println("Impresor.afterThrowing(..), metodo:"+metodo.getName()+",instancia:"+instancia.getClass().getCanonicalName());
}
@Override
public void afterReturning(Object retorno, Method metodo, Object[] argumentos,
Object instancia) throws Throwable {
System.out.println("Impresor.afterReturning(..), metodo:"+metodo.getName()+",instancia:"+instancia.getClass().getCanonicalName());
}

}


Y la configuración de spring es la siguiente:

<!-- Le indicamos a spring para que haga uso de las anotaciones @Autowired -->
<context:annotation-config/>
<!-- Le indicamos a spring que lea todas las clases bajo el paquete pe.com.slcsccy.service y sus
subpaquetes y clases, y si encuentra anotaciones estereotipadas(@Service,@Repository,@Controller)
a nivel de clase entonces cree beans del tipo singleton instanciandolas y disponiendolas al proyecto -->
<context:component-scan base-package="pe.com.slcsccy.service"/>
<!-- La definición del aspecto está embebida al implementar las interfaces *Advice -->
<bean id="impresorAspect" class="pe.com.slcsccy.aop.ImpresorAspectImpl"/>
<bean id="auditoriaAspect" class="pe.com.slcsccy.aop.AuditoriaAspectImpl"/>
<!-- Definición y configuración de los aspectos, cuando se ejecutan y su orden -->
<aop:config>
<aop:pointcut id="pointcut"
expression="execution(public * pe.com.slcsccy.service..*(..))"/>
<!-- El orden de ejecución de los aspectos en conforme ellos son declarados -->
<aop:advisor id="advisor1" advice-ref="auditoriaAspect" pointcut-ref="pointcut"/>
<aop:advisor id="advisor2" advice-ref="impresorAspect" pointcut-ref="pointcut"/>
</aop:config>

Creación de Aspectos con Spring y XML

En los dos post anteriores vimos como podemos crear aspectos mediante anotaciones y casi nada de xml más que un simple tag ahora vamos a seguir con los aspectos pero ya no con anotaciones sino con XML, los aspectos al no tener anotaciones que los configuren como aspectos toman al forma de simple java beans:

AuditoriaAspectXml.java
package pe.com.slcsccy.aop;
import pe.com.slcsccy.bean.Libro;
public class AuditoriaAspectXml {
public void auditar(Libro libroin, Object instancia) {
System.out.println("Aplicando Aspecto de auditoria auditar(..) @Before! con instancia:"+instancia.getClass().getCanonicalName());
}
}

ImpresorAspectXml.java
package pe.com.slcsccy.aop;
import pe.com.slcsccy.bean.Libro;
public class ImpresorAspectXml {
public void asignarAutor(Libro libroin, Object instancia) {
if(libroin!=null)libroin.setAutor("Carlos Cacique");
System.out.println("Aplicando Aspecto asignarAutor(..) @Before! con instancia:"+instancia.getClass().getCanonicalName());
}
}


La prueba de los aspectos se dispuso de tal forma que AuditoriaAspectXml.java se ejecute primero y antes del aspecto ImpresorAspectXml.java y que al final se ejecute la lógica de negocio.
Es decir el orden de ejecución debería ser el siguiente:

1. AuditoriaAspectXml.auditar();
2. ImpresorAspectXml.asignarAutor();
3. ImpresorService.imprimir()

La configuración mediante spring que logra lo anterior, es la siguiente:

<!-- Le indicamos a spring para que haga uso de las anotaciones @Autowired -->
<context:annotation-config/>
<!-- Le indicamos a spring que lea todas las clases bajo el paquete pe.com.slcsccy.service y sus
subpaquetes y clases, y si encuentra anotaciones estereotipadas(@Service,@Repository,@Controller)
a nivel de clase entonces cree beans del tipo singleton instanciandolas y disponiendolas al proyecto -->
<context:component-scan base-package="pe.com.slcsccy.service"/>
<!-- Creamos javabeans que nos servirá como aspecto -->
<bean id="impresorAspectXml" class="pe.com.slcsccy.aop.ImpresorAspectXml"/>
<bean id="auditoriaAspectXml" class="pe.com.slcsccy.aop.AuditoriaAspectXml"/>
<!-- Definición y configuración de los aspector propiamente dichos -->
<aop:config>
<!-- Configuración del primer aspecto de impresión y de orden=2, el atributo orden indica la secuencia
de ejecución de este aspecto cuando hay un advice que dispara varios aspectos, recuerda que un advice
es la clase en ejecución a la que le aplicamos los aspectos, en este proyecto es el
bean impresorService o instancias de la clase ImpresorServicePdf.java ó ImpresorServiceExcel.java-->
<aop:aspect ref="impresorAspectXml" order="2">
<!-- pointcut=literalmente punto de corte, indica a qué clase se le va a aplicar el aspecto, es
definido mediante expresiones regulares-->
<aop:pointcut id="pointcutImpresor"
expression="execution(public * pe.com.slcsccy.service..*(..)) and args(libroin) and target(instancia)"/>
<!-- aspecto, indica el nombre del método a ejecutar y el pointcut de referencia -->
<aop:before method="asignarAutor" pointcut-ref="pointcutImpresor" />
</aop:aspect>
<!-- Configuración del primer aspecto de impresión y de orden=1 -->
<aop:aspect ref="auditoriaAspectXml" order="1">
<aop:pointcut id="pointcutAuditoria"
expression="execution(public * pe.com.slcsccy.service..*(..)) and args(libroin) and target(instancia)" />
<aop:before method="auditar" pointcut-ref="pointcutAuditoria" />
</aop:aspect>
</aop:config>

El proyecto completo te lo puedes bajar desde AQUI: