2011-05-10 6 views
6

Tengo una versión de la aplicación Java en Spring 3. Este proyecto tiene otro jar como dependencia.¿Por qué Spring AOP no está tejiendo tarros externos en tiempo de ejecución?

Esta dependencia contiene una clase @org.aspectj.lang.annotation.Aspect (digamos, com.aspectprovider.aspects.MyAspect). Hay un consejo @Before para tejer un método de clases que implementa la interfaz Foo. Algo así como:

@Before("execution(* com.project.Foo.save(..))") 

La interfaz Foo puede estar dentro del "proyecto" o en otro frasco. No importa para este ejemplo.

Mi proyecto contiene clases que implementa Foo. Esas son las clases que quiero que sean tejidas, por supuesto.

Mi solicitud de Primavera archivo de configuración de contexto (applicationContext.xml) contiene la línea:

<aop:aspectj-autoproxy /> 

También declaro el aspecto como un bean, e inyectar algunas propiedades:

<bean id="myAspect" class="com.aspectprovider.aspects.MyAspect" 
    factory-method="aspectOf" > 
    <property name="someproperty" value="somevalue" /> 
</bean> 

Trough tala puedo ver que MyAspect se crea una instancia y las propiedades se inyectan. Pero el método de guardar no se intercepta. Este es el problema.

Si copio las clases de aspecto del jar a la aplicación que tiene Spring, funciona. Cuando esos aspectos están contenidos en jarras externas, el método de guardar no se intercepta. ¿Alguna pista?

edición: cómo me llamo método save de Foo:

//in a JSF managed bean 
@Inject 
private Foo myFoo; //there's a implementation of Foo in a package that spring is looking at. So it is injected correctly. 

public String someAction() { 
    myFoo.save("something"); //the @Before advice is only called if the class containing the aspect is not in an external jar 
} 


//in a class with a main method 
void main(String[] ars) { 
    ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); 
    //right after the previous line, I can see in the log that MyAspect is instantiated. 
    Foo myFoo = ac.getBean(Foo.class); 
    myFoo.save("something"); //the @Before advice is only called if the class containing the aspect is not in an external jar 
} 

Básicamente, mis applicationContext.xml tiene las siguientes líneas:

<context:annotation-config /> 
<context:component-scan base-package="com.project" /> 
<context:component-scan base-package="com.aspectprovider.aspects" /> 
<aop:aspectj-autoproxy /> 
<bean id="myAspect" class="com.aspectprovider.aspects.MyAspect" factory-method="aspectOf" > 
    <property name="someproperty" value="somevalue" /> 
</bean> 

no creo que tengo que poner algo como

<context:component-scan base-package="com.project"> 
    <context:include-filter type="aspectj" expression="com.aspectprovider.aspects.*" /> 
</context:component-scan> 
+0

¿Usted está funcionando bajo un environement J2EE? Weblogic websphere jboss o incluso tomcat? –

+0

es tomcat. pero tengo el mismo problema si corro a través de la consola, cargando el contexto de primavera "a mano". – bluefoot

+0

¿Cómo llamas al método 'save' en cuestión? Si no lo está llamando a través de una referencia de que Spring proporciona su código, * el corte de punto no se llamará *. El error habitual es llamar a través de 'this' (explícita o implícitamente), que es una invocación directa en la instancia envuelta y no en el propio bean. –

Respuesta

0

He terminado declarando los aspectos en applicationContext xml config de primavera y quitando las anotaciones.

Lo que funcionaba hasta ahora era usar el complemento aspectj para maven, pero cada vez que cambiaba una clase en eclipse, tenía que ejecutar $ mvn compile (porque eclipse no conoce los aspectos, y estaba compilando las clases sin ellos), y eso es algo horrible de decir a cualquiera que use MyAspect.

Luego, acabo de crear un archivo de configuración y documenté: para usar MyAspect, solo importe estas reglas de configuración a la configuración de contexto de su primavera.

+0

Estoy en la misma situación que tú; pero mi aspecto está basado en anotaciones, ¿eso sería un problema? ¿Y no necesitamos hacer tejer en tiempo de carga en esta situación? –

2

Usted puede tratar de aspectj LT W en lugar del proxy Spring AOP. Para ello añadir un aop.xml a su META-INF

<!DOCTYPE aspectj PUBLIC 
     "-//AspectJ//DTD//EN" "http://www.eclipse.org/aspectj/dtd/aspectj.dtd"> 
<aspectj> 
    <weaver> 
     <!-- only weave classes in this package --> 
     <include within="org.springbyexample.aspectjLoadTimeWeaving.*" /> 
    </weaver> 
    <aspects> 
     <!-- use only this aspect for weaving --> 
     <aspect name="org.springbyexample.aspectjLoadTimeWeaving.PerformanceAdvice" /> 
    </aspects> 
</aspectj> 

Y esta es la parte de resorte de la configuración:

Ver aquí para más detalles: http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/aop.html#aop-aj-ltw

+0

Gracias, pero ya sé sobre LTW, y estoy tratando de evitarlo por un par de razones que no creo que sea el momento de discutir. Runtime weaving funcionaba perfectamente hasta ahora. El problema comenzó cuando separé los aspectos a otro jar. – bluefoot

+0

+1 porque terminé con XML. Más información en mi respuesta. – bluefoot

0

De AspectJ en el libro de acción: aspectos utilizados con el AOP basado en proxy (declarado mediante @AspectJ o sintaxis basada en XML) son Spring Beans y no deberían usar el enfoque aspectOf() a ejemplificación.

Declárelo normalmente y ver si funciona:

<bean id="myAspect" class="com.project.MyAspect"> 
    <property name="someproperty" value="somevalue" /> 
</bean> 
+0

bueno, en realidad si no uso 'factory-method',' MyAspect' se instancia dos veces. Creo que la primera vez es por ''.Una cosa u otra, solo funciona cuando 'MyAspect' no está en un contenedor externo. – bluefoot

3

Teniendo en cuenta que funciona perfectamente bien cuando las clases se incluyen con la aplicación y la primavera sólo puedo pensar que sería una cuestión de carga de clases.

Si funciona correctamente cuando está incluido en su aplicación, entonces cuando AOP escanea todas las clases que tendrá que supervisar, se está haciendo referencia al cargador de clases correcto con todos los archivos jar correctos. Pero ahora, cuando lo elimina y lo establece en un JAR, está escaneando en el cargador de clases con todos los otros jar de terceros.

No estoy 100% seguro de lo que está trazado pero podría ser algo como esto:

Bootstrap Classloader <- Third Party Classloader <- Application Class Loader (with all your classes) 
           \       \ 
           aspectj.jar    spring.jar 

Si su aspect.jar es escaneada debajo de su cargador de clase única, entonces no será capaz de ver ' todas tus clases '. Una forma de intentar confirmar esto es obtener un volcado dinámico de su aplicación. Ejecútelo contra Eclipse MAT, consulte el explorador de Class Loader y busque las clases de aspecto. Si no residen en el mismo cargador de clases que tu aplicación, deberías buscar la forma de que tomcat comunique a las bibliotecas de terceros de las clases de la aplicación.

+0

, por lo que está diciendo que los archivos jar de terceros (incluido el que tiene los aspectos) se cargan en un cargador de clases diferente de las clases del proyecto. ¿Y el aspectj solo teje el cargador de clases "principal"? ¿es asi? – bluefoot

+1

Sí, eso es lo que sospecho. Puede probar esto encontrando el nombre de un método dentro del conjunto de bibliotecas de terceros y haciendo que el AOP intercepte esa llamada al método. Si eso funciona, entonces te estás acercando. –

+0

Bueno uno (+1). Puede ser un problema de carga de clases. Moví una de las implementaciones de 'Foo' en el jar' MyAspect', luego el método 'save()' de esta implementación fue interceptado cuando lo llamé de la manera descrita en la pregunta. Entonces, ahora que estamos seguros, ¿hay algo que se pueda hacer? – bluefoot

6

Tengo el mismo problema. Resolví este problema de empaque con maven. Compruebe el aspectj-maven-plugin y la opción weaveDependency

http://mojo.codehaus.org/aspectj-maven-plugin/weaveJars.html

+1

Eso es lo que estaba haciendo (ver [mi respuesta] (http://stackoverflow.com/questions/5956490/why-spring-aop-is-not-weaving-external-jars-at-runtime/6238001#6238001)) , pero aún así tuve que compilarlo manualmente o usando alguna herramienta externa. Estaba buscando un tiempo de carga tejiendo, no un tiempo de compilación. – bluefoot

+0

+1 funcionó para mí – Ritesh

Cuestiones relacionadas