I'm having some problems getting load-time weaving to work with Spring in my Tomcat 6 webapp. I only want to use it for transactions (so that self-invocation respects transactional annotations, which it doesn't with AOP proxying). It appears that the weaver is being loaded, but my annotated classes aren't actually being woven. When I step through my code, I don't see any transaction boundaries in SQL logs, as I was seeing with regular AOP proxy configuration. Here's my setup:
In server.xml:
<Context path="/api" allowLinking="true" reloadable="false" docBase="/usr/local/apache-tomcat-6.0.18/webapps/API/ROOT" workDir="/usr/local/apache-tomcat-6.0.18/webapps/API/ROOT/work">
<Loader loaderClass="org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader"/>
</Context>
I've got spring-tomcat-weaver.jar tomcat/lib directory, and the following jars on my Tomcat classpath:
tomcat/webapps/API/ROOT/WEB-INF/lib/aspectjweaver.jar tomcat/webapps/API/ROOT/WEB-INF/lib/spring-aspects.jar
This is in the bean config file where the annotated service classes are defined:
<tx:annotation-driven transaction-manager="txManager" mode="aspectj"/>
In one of the many other bean config files in my context:
<aop:aspectj-autoproxy>
<aop:include name="methodTimer"/>
</aop:aspectj-autoproxy>
<context:load-time-weaver aspectj-weaving="on"/>
<context:annotation-config />
<bean name="methodTimer" class="tv.current.web.aop.MethodTimer" />
I want MethodTimer to use regular AOP proxying, not LTW - LTW should only apply to @Transactional annotations. As described here: http://static.springsource.org/spring/docs/2.5.x/reference/aop.html#aop-aj-configure. If I comment out <aop:aspectj-autoproxy>
element, I don't get any of the weaving info log messages I see otherwise. Speaking of which, here they are; you can see that aspects are getting loaded but nothing is actually being woven:
Aug 28, 2009 6:34:42 PM org.apache.catalina.core.ApplicationContext log
INFO: Initializing Spring root WebApplicationContext
[TomcatInstrumentableClassLoader@34fe7e0e] info AspectJ Weaver Version 1.6.5 built on Thursday Jun 18, 2009 at 03:42:32 GMT
[TomcatInstrumentableClassLoader@34fe7e0e] info register classloader org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader@34fe7e0e
[TomcatInstrumentableClassLoader@34fe7e0e] info using configuration file:/usr/local/apache-tomcat-6.0.18/webapps/API/ROOT/WEB-INF/lib/spring-aspects.jar!/META-INF/aop.xml
[TomcatInstrumentableClassLoader@34fe7e0e] warning ignoring duplicate definition: jar:file:/usr/local/apache-tomcat-6.0.18/webapps/API/ROOT/WEB-INF/lib/spring-aspects.jar!/META-INF/aop.xml
[TomcatInstrumentableClassLoader@34fe7e0e] info register aspect org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect
[TomcatInstrumentableClassLoader@34fe7e0e] info register aspect org.springframework.transaction.aspectj.AnnotationTransactionAspect
[TomcatInstrumentableClassLoader@34fe7e0e] info processing reweavable type org.springframework.beans.factory.aspectj.AbstractInterfaceDrivenDependencyInjectionAspect$ConfigurableDeserializationSupport: org/springframework/beans/factory/aspectj/AbstractInterfaceDrivenDependencyInjectionAspect.aj
[TomcatInstrumentableClassLoader@34fe7e0e] info successfully verified type org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect exists. Originates from org/springframework/beans/factory/aspectj/D:\projects\spring\spring\aspectj\src\org\springframework\beans\factory\aspectj\AnnotationBeanConfigurerAspect.aj
[TomcatInstrumentableClassLoader@34fe7e0e] info successfully verified type org.springframework.beans.factory.aspectj.AbstractInterfaceDrivenDependencyInjectionAspect exists. Originates from org/springframework/beans/factory/aspectj/D:\projects\spring\spring\aspectj\src\org\springframework\beans\factory\aspectj\AbstractInterfaceDrivenDependencyInjectionAspect.aj
[TomcatInstrumentableClassLoader@34fe7e0e] weaveinfo Type 'org.springframework.beans.factory.aspectj.AbstractInterfaceDrivenDependencyInjectionAspect$ConfigurableDeserializationSupport' (AbstractInterfaceDrivenDependencyInjectionAspect.aj) has intertyped method from 'org.springframework.beans.factory.aspectj.AbstractInterfaceDrivenDependencyInjectionAspect' (D:\projects\spring\spring\aspectj\src\org\springframework\beans\factory\aspectj\AbstractInterfaceDrivenDependencyInjectionAspect.aj:'java.lang.Object org.springframework.beans.factory.aspectj.AbstractInterfaceDrivenDependencyInjectionAspect$ConfigurableDeserializationSupport.readResolve()')
As you can see from the logs, I don't have my own aop.xml file, I am using the default one in spring-aspects.jar, which is as follows:
<aspectj>
<!--
<weaver options="-showWeaveInfo"/>
-->
<aspects>
<aspect name="org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect"/>
<aspect name="org.springframework.transaction.aspectj.AnnotationTransactionAspect"/>
</aspects>
</aspectj>
I don't need to start Tomcat with -javaagent:/path/to/spring-agent.jar
, correct? Because I specified the right ClassLoader in server.xml and am seeing the loader getting used. Am I mistaken about this? Do I need spring-agent.jar anywhere, either in tomcat/lib or my tomcat classpath? Do I need aspectjweaver.jar in tomcat/lib? What else am I missing? Any help would be greatly appreciated as I have been wrestling with this for almost two days now.
Edit: One more (perhaps very important) detail I omitted - I'm developing in Eclipse and using the Sysdeo Tomcat Plugin to start Tomcat. Will try starting Tomcat from the command line and see if that makes a difference...
It turned out that it was the Eclipse plugin I was using to start Tomcat. Our whole team has become reliant on it, never starting Tomcat from the command line on our local machines. It does something with the classloader that broke LTW. When I finally got Tomcat started from the command line, everything worked perfectly. For the record, you do NOT need -javaagent:path/to/spring-agent.jar if you specify TomcatInstrumentableClassLoader in server.xml.