Default style (Cherry Eve). Switch styles (Capricorn). Atom Feed Calendar
http://weblogs.javahispano.org/jlmonteagudo/date/20060717 lunes julio 17, 2006

Spring AOP

Spring AOP

Spring AOP

El propósito de este artículo es ver de qué forma podemos trabajar con AOP con la implementación que Spring nos proporciona. Hay varios frameworks AOP, muchos de ellos open source ( AspectWerkz, AspectJ, Jboss AOP, dynaop ), pero en este artículo nos vamos a centrar en Spring AOP.

La primera vez que nos sumergimos en el mundo de AOP nos encontramos con una serie de nuevos conceptos que pueden ser no muy sencillos de digerir vistos desde un punto de vista teórico, pero si ponemos a trabajar a estos conceptos dentro del campo de batalla vemos que no resulta tan difícil como a priori parece. Por ello, éste va a ser un artículo meramente práctico, por lo que si el lector quiere disponer de un conocimiento teórico del mundo AOP tendrá que remitirse a otros artículos que explican la teoría en profundidad.

La implementación AOP de Spring se basa en la regla 80-20, lo cual significa que con Spring podemos realizar el 80% de las funciones que con AOP se pueden realizar, pero si queremos implementar el otro 20% tendremos que recurrir a otros frameworks más especializados. No hay que asustarse por este dato ni descartar la implementación AOP de Spring por ello, ya que prácticamente cualquier cosa que queramos hacer con AOP entrará dentro de este 80%.

AOP es útil para realizar tareas puntuales que no encajan de forma natural en nuestras entidades ni en nuestra lógica de negocio; estas tareas podríamos implementarlas en la lógica de negocio por ejemplo, pero estaríamos ensuciando nuestras clases con código que no les corresponde controlar. Imagínemos por ejemplo el envío de un mail al administrador cuando un usuario nuevo ha sido dado de alta. La función de enviar un mail no está relacionada en absoluto con las funciones que debería de hacer una clase encargada que administrar usuarios. Para no mezclar estas funciones podríamos utilizar perfectamente AOP y definir fuera de nuestro código que cuando se dé de alta un usario nuevo se envíe un mail a una dirección determinada. Hay varios campos para los que AOP se puede emplear de forma satisfactoria, como puede ser para realizar Transacciones, para Depurar un programa registrando lo que está sucediendo en los métodos, o para implementar unas políticas de seguridad. Spring tiene implementadas clases para controlar el tema de las Transacciones y el de registro de acciones. También existe un framework de seguridad ( Acegi ) que va a formar parte de Spring. Pero si queremos implementar otro tipo de aspectos personalizados debemos definirlos nosotros mismos implementando unas interfaces creadas para tal efecto, y precisamente éste va a ser el objetivo de este artículo, la definición de aspectos personalizados en Spring.

Demostración de Spring AOP con un sencillo ejemplo

Vamos a empezar a ponernos manos a la obra con un pequeño ejemplo. Este ejemplo sólo pretende mostrar cómo trabaja Spring AOP.

El árbol de directorio con el que vamos a trabajar va a ser el siguiente :

Vamos a tener una entidad Usuario y una intefaz UsuarioService que nos va a permitir realizar las operaciones típicas ( CRUD ) que con una entidad se pueden realizar :

    - Create : 	Creación de un usuario nuevo
    - Retrieve :	Consulta de un usuario existente
    - Update :	Actualización de usuario
    - Delete :	Borrado de usuario

Por otra parte tenemos una serie de Advices que no son más que clases Java que implementan una interfaz determinada y que es el código que se ejecuta antes, después o durante la llamada a uno de los métodos de la interface UsuarioService. También se podrían ejecutar en el momento en el que ocurre una excepción.

Tipos de Advices en Spring AOP

Antes de continuar con el ejemplo hay que dejar claro que con Spring hay varios tipos de Advices, y según cuál de ellos queramos implementar hay que implementar una u otra interface :

    - Before : para implementar este tipo de advice tenemos que 
      implementar la interface 
      org.springframework.aop.MethodBeforeAdvice. 
      Es fácil de intuir que este advice se ejecutará 
      siempre antes de la llamada a un método.

    - After Returning : la interfaz a implementar para realizar un 
      advice de este tipo es 
      org.springframework.aop.AfterReturningAdvice. Este advice 
      se ejecuta después de la llamada a un método.

    - Around : hay que implementar la interfaz 
      org.aopalliance.intercept.MethodInterceptor.Cuando 
      implementamos un advice de este tipo podremos realizar acciones 
      antes y después de invocar el método interceptado.

    - Throws : hay que implementar 
      org.springframework.aop.ThrowsAdvice. Se ejecuta cuando 
      ocurre una excepción.

Para llevar a cabo el ejemplo vamos a tener de definir en primer lugar dos clases más una interfaz y podremos ver rápidamente cómo estas clases son completamente independientes de los aspectos que definamos posteriormente. Esto significa que a cualquier aplicación que tengamos ya en producción podremos añadirle cierta funcionalidad sin tener que retocar nada del código escrito hasta ahora.

Definimos en primer lugar nuestra entidad Usuario


package sample.model;

public class Usuario extends BaseObject {

    private String nombre;
    private String apellidos;
    private String direccion;

    public String getNombre() {
        return nombre;
    }

    public void setNombre(String nombre) {
        this.nombre = nombre;
    }

    public String getApellidos() {
        return apellidos;
    }

    public void setApellidos(String apellidos) {
        this.apellidos = apellidos;
    }

    public String getDireccion() {
        return direccion;
    }

    public void setDireccion(String direccion) {
        this.direccion = direccion;
    }


}

A continuación definimos una interfaz con los métodos necesarios para administrar nuestra entidad Usuario


package sample.service;

import sample.model.Usuario;

public interface UsuarioService {

    public Usuario consultaUsuario( Usuario usuario );
    public boolean agregarUsuario( Usuario usuario );
    public int actualizarUsuario( Usuario usuario );
    public boolean borrarUsuario( Usuario usuario );
    public void procesarInformacion();

}

Y por último creamos una clase que implementa la interfaz anterior; la implementación de la interfaz en este ejemplo es completamente trivial para que el lector pueda probar fácilmente la aplicación; además la única función en este artículo es ver cómo trabajar con Spring AOP, aunque no resulta nada complicado cambiar la implementación de esta clase para que interactue con una base de datos.


package sample.service.impl;

import sample.model.Usuario;
import sample.service.UsuarioService;

public class UsuarioServiceImpl implements UsuarioService {

    public Usuario consultaUsuario( Usuario usuario ) {
        System.out.println( "Consultando el Usuario : " + usuario );
        return usuario;
    }

    public boolean agregarUsuario( Usuario usuario ) {
        System.out.println( "Insertando Usuario : " + usuario );
        return true;
    }

    public int actualizarUsuario( Usuario usuario ) {
        System.out.println( "Actualizando Usuario : " + usuario );
        return 1;
    }

    public boolean borrarUsuario( Usuario usuario ) {
        System.out.println( "Borrando Usuario : " + usuario );
        return true;
    }

    public void procesarInformacion() {

        try {

            Thread tarea = new Thread( new Runnable() {
                public void run() {}
            }
            );
            tarea.start();
            tarea.sleep( 5000 );
        }
        catch( Exception e ) {
            e.printStackTrace();
        }

    }

}

Como podemos ver, estas clases pueden trabajar perfectamente de forma independiente. Es decir, no necesitan extender ninguna clase ni implementar ninguna interfaz para que puedan trabajar. Podríamos hacerlas funcionar en cualquier contenedor. De hecho, ahora vamos a hacerlas funcionar dentro del contenedor de Spring.

Para conseguir que este conjunto de clases trabaje dentro del contenedor de Spring no tenemos que realizar mucho trabajo. Tan solo tenemos que declarar de la siguiente forma un bean en el fichero de configuración applicationContext.xml :


<beans>

    <bean id = "usuarioService" class = "sample.service.impl.UsuarioServiceImpl"/>

</beans>

A continuación vamos a crear una clase con un método main() para poner a trabajar el bean que hemos definido anteriormente :


package sample;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
import sample.model.Usuario;
import sample.service.UsuarioService;

public class Principal {

    private static ApplicationContext ctx;
    private Usuario usuario = new Usuario();

    public Principal() {

        String[] paths = {  "src/sample/applicationContext.xml" };
        ctx = new FileSystemXmlApplicationContext(paths);

        usuario.setNombre( "USUARIO_NOMBRE" );
        usuario.setApellidos( "USUARIO_APELLIDOS" );
        usuario.setDireccion( "USUARIO_DIRECCION" );
    }

    public static void main(String[] args) {

        Principal programa = new Principal();
        programa.test ();
    }

    public void test () {

        UsuarioService service = (UsuarioService)ctx.getBean( "usuarioService" );
        service.consultaUsuario( usuario );
    }
}

Como vemos, es muy sencillo hacer trabajar estas clases; volvemos a hacer hincapié en la trivialidad de la implementación de los métodos de la clase UsuarioServiceImpl; en un entorno real el método consultaUsuario lo que tendría que realizar sería un acceso a una base datos para retornar un usuario, pero como lo que aquí nos interesa es AOP, no vamos a emplear tiempo en la implementación de la clase.

Ahora, lo que nos interesa es ver cómo vamos a incrementar la funcionalidad de estas clases ( la funcionalidad de UsuarioServiceImpl en particular ) sin tener que modificar ni una línea su código. Aquí es donde entra en juego AOP.

Advice de tipo Before

Como se especificó unas líneas más arriba, Spring nos brinda la posibilidad de trabajar con distintos tipos de Advices, y el primero que vamos a ver es el Advice de tipo Before.

Cuando interceptamos un método de una clase con un Advice de tipo Before lo que sucede es que antes de ejecutarse el método se ejecuta el código del Advice. Dentro del Advice vamos a tener acceso tanto al método de la clase a la que vamos a llamar, como a los argumentos que se le pasan al método, como al objeto al que le estamos aplicando el advice.

El único proceso que tenemos que realizar para implementar un Advice de tipo Before es crear una clase que implemente la interfaz MethodBeforeAdvice. La interfaz está definida de la siguiente forma :



public interface MethodBeforeAdvice extends BeforeAdvice {
	
	/**
	 * Callback before a given method is invoked.
	 * @param method method being invoked
	 * @param args arguments to the method
	 * @param target target of the method invocation. May be null.
	 * @throws Throwable if this object wishes to abort the call.
	 * Any exception thrown will be returned to the caller if it's
	 * allowed by the method signature. Otherwise the exception
	 * will be wrapped as a runtime exception.
	 */
	void before(Method method, Object[] args, Object target) throws Throwable;

}

Vamos a crear un Advice que no tiene mucha funcionalidad, pero que nos sirve para ver cómo funciona este tipo de Advice. Lo único que hace esta clase es modificar el parámetro que se le pasa al método, y una vez modificado lo imprime por la pantalla. Como vemos, lo que hace esta clase no es nada interesante, pero le podríamos dar otro tipo de funcionalidad como podría ser implementar un control de accesos al método.

La interfaz la podemos implementar como sigue :


package sample.aop.advice;

import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
import sample.model.Usuario;

public class EventoBeforeAdvice implements MethodBeforeAdvice {

    public void before( Method method, Object[] parameters, Object target ) throws Throwable {

        System.out.println( "***************** AOP BEFORE ADVICE *********************" );
        Usuario usuario = (Usuario)parameters[0];
        usuario.setNombre( usuario.getNombre() + " MODIFICADO POR AOP" );
        System.out.println( "AOP BEFORE ADVICE : Accediendo al Usuario " + usuario );

    }
}

Ahora lo único que faltaría hacer sería especificar que cuando se realice la llamada a un método de una clase que sea interceptado por este advice. Para conseguir esto lo único que tenemos que hacer es declararlo en el fichero applicationContext :


<beans>

    <bean id = "usuarioServiceTarget" class = "sample.service.impl.UsuarioServiceImpl"/>

    <bean id = "eventoBeforeAdvice" class = "sample.aop.advice.EventoBeforeAdvice"/>

    <bean id = "usuarioService" class = "org.springframework.aop.framework.ProxyFactoryBean">

        <property name = "proxyInterfaces">
            <value>sample.service.UsuarioService</value>
        </property>

        <property name = "interceptorNames">
            <list>
                <value>eventoBeforeAdvice</value>
            </list>
        </property>

        <property name = "target">
            <ref bean = "usuarioServiceTarget"/>
        </property>

    </bean>

</beans>

Como vemos, en primer lugar tenemos que cambiar la definición que teníamos del bean usuarioService. Antes estaba definido así :

<bean id = "usuarioService" class = "sample.service.impl.UsuarioServiceImpl"/>

y ahora lo definimos así :

<bean id = "usuarioServiceTarget" class = "sample.service.impl.UsuarioServiceImpl"/>

El siguiente paso es declarar un bean del advice que habíamos creado :

<bean id = "eventoBeforeAdvice" class = "sample.aop.advice.EventoBeforeAdvice"/>

Y por último, lo que nos queda es definir un proxy para el bean usuarioServiceTarget. A este proxy le tenemos que decir :

    - qué interfaz tiene que implementar : UsuarioService
    - qué interceptores queremos aplicar : eventoBeforeAdvice
    - a qué bean queremos aplicar los interceptores : usuarioServiceTarget

Con estos cambios realizados en el fichero applicationContext ya podríamos probar de nuevo la clase Principal que habíamos creado anteriormente. No es necesario que modifiquemos ninguna línea de código de las clases anteriores; vemos que lo único que hemos hecho ha sido crear una nueva clase, y modificar el fichero de configuración de Spring. Si ejecutamos de nuevo la clase Principal obtendríamos el siguiente resultado :



******************** AOP BEFORE ADVICE ************************
AOP BEFORE ADVICE : Accediendo al Usuario sample.model.Usuario@a4488[
  nombre=USUARIO_NOMBRE MODIFICADO POR AOP
  apellidos=USUARIO_APELLIDOS
  direccion=USUARIO_DIRECCION
]
Consultando el Usuario : sample.model.Usuario@a4488[
  nombre=USUARIO_NOMBRE MODIFICADO POR AOP
  apellidos=USUARIO_APELLIDOS
  direccion=USUARIO_DIRECCION
]

En este ejemplo podemos comprobar cómo se pueden manipular parámetros que se le envian al método interceptado. No estoy seguro que sea una buena práctica realizar este tipo de cosas dentro de un advice, pero lo hacemos simplemente para demostrar que podemos manipular parámetros dentro del advice.

Pues con esto ya estaríamos aplicando AOP a nuestras clases. Pero si modificamos la clase Principal para que haga llamadas a otros métodos de la clase UsuarioServiceImpl además de al método consultaUsuario vemos que todos los métodos son interceptados. Necesitamos algo más de flexibilidad, necesitamos poder especificar a qué métodos se les aplica qué advices, cosa que vamos a conseguir con los PointCuts.

Definiendo PointCuts

Pues bien, un PointCut no es más que definir qué métodos van a ser interceptados con qué advices. No tenemos por qué especificar el nombre del método completo, sino que podemos utilizar comodines para decir que se intercepten todos aquellos métodos que empiecen por unas palabras determinadas, o que acaben o contegan otras palabras, es decir, podemos establecer que se intercepten aquellos métodos que cumplan un determinado patrón.

La forma más sencilla de definir PointCuts es a través de la clase RegexpMethodPointcut que ya viene implementada en Spring. Como vamos a ver a continuación no necesitamos escribir nuevo código, simplemente se trata de configurar correctamente el fichero applicationContext :


<bean id = "consultaPointCut" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">

        <property name = "pattern">
            <value>.*consulta.*</value>
        </property>
        <property name = "advice">
            <ref bean = "eventoBeforeAdvice"/>
        </property>
</bean>

Por último nos faltaría una cosa más. Tenemos que cambiar lo siguiente en la declaración del bean usuarioService :


<bean id = "usuarioService" class = "org.springframework.aop.framework.ProxyFactoryBean">

        <property name = "proxyInterfaces">
            <value>sample.service.UsuarioService</value>
        </property>

        <property name = "interceptorNames">
            <list>
               <value>eventoBeforeAdvice</value>
            </list>
        </property>

        <property name = "target">
            <ref bean = "usuarioServiceTarget"/>
        </property>

</bean>

Por esto otro :


<bean id = "usuarioService" class = "org.springframework.aop.framework.ProxyFactoryBean">

        <property name = "proxyInterfaces">
            <value>sample.service.UsuarioService</value>
        </property>

        <property name = "interceptorNames">
            <list>
               <value>consultaPointCut</value>
            </list>
        </property>

        <property name = "target">
            <ref bean = "usuarioServiceTarget"/>
        </property>

    </bean>

Con esta configuración, como se puede intuir, lo que conseguimos es que cuando hagamos una llamada al método consultaUsuario del bean usuarioService, antes de ejecutarse el código del método se ejecute el código del advice que hemos configurado.

Advice de tipo After Returning

Anteriormente hemos estado viendo lo sencillo que resulta aplicar advices de tipo before a clases que ya tenemos creadas. Ahora vamos a tratar los advices de tipo after returning pero sin detenernos en dar muchos detalles de cómo se implementa, ya que la forma de declararlos es idéntica a los anteriores. La única diferencia estriba en la clase que tenemos que implementar a la hora de crear el advice, que en este caso nuestra clase va a tener que implementar la interface AfterReturningAdvice :


public interface AfterReturningAdvice extends Advice {
	
	/**
	 * Callback after a given method successfully returned.
	 * @param returnValue the value returned by the method, if any
	 * @param method method being invoked
	 * @param args arguments to the method
	 * @param target target of the method invocation. May be null.
	 * @throws Throwable if this object wishes to abort the call.
	 * Any exception thrown will be returned to the caller if it's
	 * allowed by the method signature. Otherwise the exception
	 * will be wrapped as a runtime exception.
	 */
	void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable;

}

Como vemos en la definición de la interfaz, cuando la implementemos podremos trabajar con el método del objeto que fue llamado, con los parámetros que se le pasaron al método, con el objeto al que se le ha interceptado la llamada al método y además con el valor que el método ha devuelto.

A continuación vamos a crear una clase que implemente esta interfaz. De nuevo, la implementación de esta clase va a ser trivial, aunque le podríamos dar funcionalidad un poco más interesante haciendo por ejemplo que cuando se dé de alta un usuario nuevo envíe automáticamente un mail al administrador del sistema informándole de que tal usuario ha sido dado de alta ( no lo vamos a implementar en este ejemplo ).

Creamos la clase de la siguiente forma :


package sample.aop.advice;

import org.springframework.aop.AfterReturningAdvice;
import java.lang.reflect.Method;
import sample.model.Usuario;

public class EventoAfterAdvice implements AfterReturningAdvice {

    public void afterReturning( Object valueReturned, Method method, Object[] parameters, Object target ) throws Throwable {

        System.out.println( "***************** AOP AFTER ADVICE *********************" );
        int records = ((Integer)valueReturned).intValue();
        if ( records == 1 ) {
            System.out.println( "AOP AFTER ADVICE : Nº Registros actualizados : " + records );
            System.out.println( "MAIL ENVIADO AL ADMINISTRADOR" );
        }
        else {
            System.out.println( "AOP AFTER ADVICE : NO se ha actualizado ningún registro" );
        }

    }

}

Registramos el advice en el fichero de configuración de Spring :

<bean id = "eventoAfterAdvice" class = "sample.aop.advice.EventoAfterAdvice"/>

Creamos un nuevo PointCut para que se ejecute este advice siempre que se invoque a algún método que contenga la palabra actualizar :


<bean id = "actualizaPointCut" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
        <property name = "pattern">
            <value>.*actualizar.*</value>
        </property>
        <property name = "advice">
            <ref bean = "eventoAfterAdvice"/>
        </property>
</bean>

Agregamos el PointCut al bean usuarioService :


<bean id = "usuarioService" class = "org.springframework.aop.framework.ProxyFactoryBean">

        <property name = "proxyInterfaces">
            <value>sample.service.UsuarioService</value>
        </property>

        <property name = "interceptorNames">
            <list>
                <value>consultaPointCut</value>
                <value>actualizaPointCut</value>
            </list>
        </property>

        <property name = "target">
            <ref bean = "usuarioServiceTarget"/>
        </property>

</bean>

Así de simple hemos configurado nuestro bean para que sea interceptado.

Advice de tipo Around

Finalmente, el último tipo de advice que de forma rápida vamos a ver en este artículo es el advice de tipo Around. Nos faltaría también ver el de tipo Throws, pero no lo vamos a ver en este artículo, ya que visto cómo se configuran los advices que hemos visto hasta ahora no resulta complicado configurar el de tipo Throws.

Según nos dicen en el manual de referencia de Spring, el advice de tipo Around es el tipo de advice más general, de hecho, muchos frameworks AOP tan sólo ofrecen este tipo de advice.

Este tipo de advice es una especie de fusión de los advices Before y After Returning. Es decir, cuando un método es interceptado por este tipo de advice podemos controlar qué hacer antes de que el método sea invocado, podemos decidir si invocamos o no el método y finalmente podemos realizar más operaciones una vez el método haya finalizado.

De forma breve vamos a ver cómo se implementa este tipo de advice. En primer lugar tenemos que implementar la interfaz org.aopalliance.intercept.MethodInterceptor. El ejemplo que vamos a realizar consiste en un sencillo trabajo que se basa en calcular el tiempo que tarda en ejecutarse el método que interceptamos. La clase es la siguiente :


package sample.aop.advice;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import sample.model.Usuario;

public class EventoMethodInterceptorAdvice implements MethodInterceptor {

    public Object invoke( MethodInvocation methodInvocation ) throws Throwable {

            System.out.println( "****** INICIO AOP METHOD INTERCEPTOR ADVICE **********" );

            long tiempoInicial = new java.util.Date().getTime();
            Object objeto = methodInvocation.proceed();
            long tiempoEjecucion = ( new java.util.Date().getTime() - tiempoInicial ) / 1000;

            System.out.println( "Nombre del Método : " + methodInvocation.getMethod() );
            System.out.println( "Tiempo de proceso del método ( segundos ) : " + tiempoEjecucion );
            System.out.println( "******* FIN AOP METHOD INTERCEPTOR ADVICE **********" );

            return objeto;

    }

}

Y a continuación configuramos el advice y el bean que tiene que ser interceptado por este advice.

Declaramos el advice :

<bean id = "eventoMethodInterceptorAdvice" class = "sample.aop.advice.EventoMethodInterceptorAdvice"/>

Declaramos el PointCut :


<bean id = "procesaPointCut" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">

        <property name = "pattern">
            <value>.*procesar.*</value>
        </property>
        <property name = "advice">
            <ref bean = "eventoMethodInterceptorAdvice"/>
        </property>
    </bean>

Y por último agregamos el interceptor al bean :


<bean id = "usuarioService" class = "org.springframework.aop.framework.ProxyFactoryBean">

        <property name = "proxyInterfaces">
            <value>sample.service.UsuarioService</value>
        </property>

        <property name = "interceptorNames">
            <list>
                <value>consultaPointCut</value>
                <value>actualizaPointCut</value>
                <value>procesaPointCut</value>
            </list>
        </property>

        <property name = "target">
            <ref bean = "usuarioServiceTarget"/>
        </property>

</bean>

Y con esto ya habríamos finalizado la configuración de nuestras clases para que sean interceptadas.

Conclusión

Con este artículo se ha pretendido demostrar que tabajar con Spring AOP resulta bastante sencillo. No se ha intentado explicar la teoría de AOP ni cuáles son las áreas más idóneas en las que AOP puede ponerse a trabajar, por lo contrario ha sido un artículo meramente práctico en el que se ha trabajado la mayoría de los tipos de advices con que cuenta Spring.

En próximos artículos sobre AOP, si se considera oportuno, se podría tratar cómo declarar Transacciones con Spring ( cosa muy sencilla una vez hemos comprendido cómo trabaja Spring AOP ), cómo hacer Logging ( más sencillo todavía ) y/o cómo implementar seguridad con Acegi.


El código fuente puede ser bajado desde aquí

Comentarios:

Execelente articulo, bien sencillo y facil de entender. Muchas gracias

Enviado por German en agosto 26, 2006 a las 04:43 PM GMT-01:00 #

Hola buenas, tengo el siguiente problema integrando log4j con el capturador de eventos de spring, el caso es que yo ya tengo un proxy padre del que heredan mis servicios, hecho así para controlar el tema de la transaccionalidad, os adjunto como esta el código a ver si alguien puede echarme un cable de como integrar un interceptor por favor!!

mi clase padre:
<!-- Transaction Manager -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource"> <ref bean="dataSource"/> </property>
</bean>

<bean id="baseTransactionProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
abstract="true">
<property name="transactionManager" ref="transactionManager"/>
<property name="transactionAttributes">
<props>
<prop key="get*">
PROPAGATION_REQUIRED,
readOnly,ISOLATION_DEFAULT
</prop>
<prop key="*">
PROPAGATION_REQUIRED,
ISOLATION_DEFAULT
</prop>
</props>
</property>
</bean>

Y ahora como tengo definidos mi DAO y mi servicio:

<bean id="StocksDAO" class="es.pss.ehm.example.ibatis.dao.StocksDAOImpl">
<property name="sqlMapClient"><ref bean="sqlMapClient"/></property>
</bean>

<bean id = "eventoBeforeAdvice" class = "es.pss.ehm.example.aop.advice.EventoBeforeAdvice"/>

<!-- Service beans Definition -->
<bean id="StocksService" parent="baseTransactionProxy">
<property name="target">
<bean class="es.pss.ehm.example.ibatis.services.StocksServiceImpl">
<constructor-arg index="0" ref="StocksDAO"/>
</bean>
</property>
</bean>

Esta configuración funciona sin problemas, ahora quiero ver como poder integrar el advice sin estropear mucho mi patrón de diseño...¿es posible?, he probado de varias maneras y siempre me da el error de:

El error le producto cuando a la definicion del bean StocksService, le introduzco la nueva propiedad de:

<property name = "interceptorNames">
<list>
<value>eventoBeforeAdvice</value>
</list>
</property>

¿que hago mal?, ¿que me falta o me sobra?, supongo que será posible seguir con la lógica que tengo de herencia mediante parent y además integrarle los advices verdad?, ahi les dejo la excepcion:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'StocksService' defined in ServletContext resource [/WEB-INF/spring/applicationContext.xml]: Error setting property values; nested exception is org.springframework.beans.NotWritablePropertyException: Invalid property 'interceptorNames' of bean class [org.springframework.transaction.interceptor.TransactionProxyFactoryBean]: Bean property 'interceptorNames' is not writable or has an invalid setter method: Does the parameter type of the setter match the return type of the getter?
org.springframework.beans.NotWritablePropertyException: Invalid property 'interceptorNames' of bean class [org.springframework.transaction.interceptor.TransactionProxyFactoryBean]: Bean property 'interceptorNames' is not writable or has an invalid setter method: Does the parameter type of the setter match the return type of the getter?
at org.springframework.beans.BeanWrapperImpl.setPropertyValue(BeanWrapperImpl.java:670)
at org.springframework.beans.BeanWrapperImpl.setPropertyValue(BeanWrapperImpl.java:572)

Enviado por miguelo en noviembre 17, 2006 a las 07:47 AM GMT-01:00 #

Para concretar mas, lo que yo quiero es seguir aplicando la transacionalidad a mis objetos DAO y Services, y ademas añadirle la posibilidad de los adviceEvents mediante la propiedad interceptorNames, proxyInterfaces y demas...

Enviado por miguelo en noviembre 17, 2006 a las 11:03 AM GMT-01:00 #

mierda

Enviado por 195.53.213.6 en enero 30, 2007 a las 08:36 AM GMT-01:00 #

Que informacion manejo en BaseObject???????????

Enviado por colette lopez en junio 16, 2008 a las 10:49 PM GMT-01:00 #

Enviar un comentario:
  • Sintaxis HTML: Deshabilitado