Announcement Announcement Module
Collapse
No announcement yet.
Load-time weaving with AspectJ and @Configurable doesn't autowire or call advice . Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Load-time weaving with AspectJ and @Configurable doesn't autowire or call advice .

    SOLVED: See reply below.

    I've been at this all day, and I've tried 3 different load-time weaving mechanisms: TomcatInstrumentableClassLoader, Spring javaagent, and AspectJ javaagent. None of them work, although the AspectJ javaagent seems to give the most positive log output.

    The Tomcat class loader method simply wouldn't expose any of my classes for weaving. I got a long list of hibernate classes, but none of my domain entities would show up in the log. The Spring javaagent wasn't any better. Finally, I removed the <context:load-time-weaver /> instruction and launched with the AspectJ weaver as a java agent. Here's the full startup log (note the AspectJ block, and Join point MyEntityListener.<init>()):

    Code:
    INFO: Initializing ProtocolHandler ["http-bio-8080"]
    [AspectJ] AspectJ Weaver Version 1.6.12 built on Tuesday Oct 18, 2011 at 17:52:06 GMT
    [AspectJ] register classloader org.apache.catalina.loader.WebappClassLoader@5c71949b
    [AspectJ] using configuration /D:/fcps/workspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps/ltw-test/WEB-INF/classes/META-INF/aop.xml
    [AspectJ] using configuration file:/D:/fcps/workspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps/ltw-test/WEB-INF/lib/org.springframework.aspects-3.1.0.RELEASE.jar!/META-INF/aop.xml
    [AspectJ] register aspect org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect
    [AspectJ] register aspect org.springframework.scheduling.aspectj.AnnotationAsyncExecutionAspect
    [AspectJ] register aspect org.springframework.transaction.aspectj.AnnotationTransactionAspect
    [AspectJ] register aspect org.springframework.cache.aspectj.AnnotationCacheAspect
    [AspectJ] Join point 'method-execution(java.lang.String ltw.test.AddContentImpl.addContent(java.lang.String))' in Type 'ltw.test.AddContentImpl' (AddContentImpl.java:25) advised by before advice from 'org.springframework.transaction.aspectj.AnnotationTransactionAspect' (AbstractTransactionAspect.aj:60)
    [AspectJ] Join point 'method-execution(java.lang.String ltw.test.AddContentImpl.addContent(java.lang.String))' in Type 'ltw.test.AddContentImpl' (AddContentImpl.java:25) advised by afterThrowing advice from 'org.springframework.transaction.aspectj.AnnotationTransactionAspect' (AbstractTransactionAspect.aj:67)
    [AspectJ] Join point 'method-execution(java.lang.String ltw.test.AddContentImpl.addContent(java.lang.String))' in Type 'ltw.test.AddContentImpl' (AddContentImpl.java:25) advised by afterReturning advice from 'org.springframework.transaction.aspectj.AnnotationTransactionAspect' (AbstractTransactionAspect.aj:77)
    [AspectJ] Join point 'method-execution(java.lang.String ltw.test.AddContentImpl.addContent(java.lang.String))' in Type 'ltw.test.AddContentImpl' (AddContentImpl.java:25) advised by after advice from 'org.springframework.transaction.aspectj.AnnotationTransactionAspect' (AbstractTransactionAspect.aj:82)
    [AspectJ] Extending interface set for type 'ltw.test.MyEntityListener' (MyEntityListener.java) to include 'org.springframework.beans.factory.aspectj.ConfigurableObject' (AnnotationBeanConfigurerAspect.aj)
    [AspectJ] Join point 'initialization(void org.springframework.beans.factory.aspectj.ConfigurableObject.<init>())' in Type 'ltw.test.MyEntityListener' (MyEntityListener.java:15) advised by before advice from 'org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect' (AbstractDependencyInjectionAspect.aj:78) [with runtime test]
    [AspectJ] Join point 'initialization(void org.springframework.beans.factory.aspectj.ConfigurableObject.<init>())' in Type 'ltw.test.MyEntityListener' (MyEntityListener.java:15) advised by afterReturning advice from 'org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect' (AbstractDependencyInjectionAspect.aj:87) [with runtime test]
    [AspectJ] Join point 'initialization(void ltw.test.MyEntityListener.<init>())' in Type 'ltw.test.MyEntityListener' (MyEntityListener.java:15) advised by afterReturning advice from 'org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect' (AbstractDependencyInjectionAspect.aj:87) [with runtime test]
    [AspectJ] javax.* types are not being woven because the weaver option '-Xset:weaveJavaxPackages=true' has not been specified
    INFO: No Spring WebApplicationInitializer types detected on classpath
    INFO: Initializing Spring FrameworkServlet 'spring'
    INFO  o.s.web.servlet.DispatcherServlet - FrameworkServlet 'spring': initialization started
    INFO  o.s.w.c.s.XmlWebApplicationContext - Refreshing WebApplicationContext for namespace 'spring-servlet': startup date [Wed Jan 25 20:46:14 AST 2012]; root of context hierarchy
    INFO  o.s.b.f.xml.XmlBeanDefinitionReader - Loading XML bean definitions from ServletContext resource [/WEB-INF/spring-servlet.xml]
    INFO  o.s.b.f.xml.XmlBeanDefinitionReader - Loading XML bean definitions from class path resource [META-INF/ltw-test-context.xml]
    INFO  o.s.o.j.LocalContainerEntityManagerFactoryBean - Building JPA container EntityManagerFactory for persistence unit 'ltw-test'
    (hibernate logging)
    (MVC mappings)
    (above: removed bean list and did some cleanup to shorten post length)

    I tried to keep things as simple as I could, to the point where I created this project from scratch in reflection of the project I first had the problem with, to get a small(ish) test project. Here's my META-INF/persistence.xml:

    Code:
    <?xml version="1.0" encoding="UTF-8"?>
    <persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    
    	<persistence-unit name="ltw-test" transaction-type="RESOURCE_LOCAL">
    		<provider>org.hibernate.ejb.HibernatePersistence</provider>
    		<non-jta-data-source>java:comp/env/jdbc/ltw-test</non-jta-data-source>
    		<properties>
    			<property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect" />
    			<property name="hibernate.hbm2ddl.auto" value="create"/>
    		</properties>
    	</persistence-unit>
    
    </persistence>
    And my META-INF/aop.xml:

    Code:
    <!DOCTYPE aspectj PUBLIC "-//AspectJ//DTD//EN" "http://www.eclipse.org/aspectj/dtd/aspectj.dtd">
    <aspectj>
    
    	<weaver options="-showWeaveInfo -XmessageHandlerClass:org.springframework.aop.aspectj.AspectJWeaverMessageHandler">
    		<include within="ltw.test.*" />
    	</weaver>
    
    </aspectj>
    My application context XML (WEB-INF/spring-servlet.xml):

    Code:
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    		xmlns:tx="http://www.springframework.org/schema/tx"
    		xmlns:context="http://www.springframework.org/schema/context"
    		xmlns:util="http://www.springframework.org/schema/util"
    		xmlns:jee="http://www.springframework.org/schema/jee">
    
    	<context:annotation-config />
    	<context:component-scan base-package="ltw.test" />
    	<context:spring-configured />
    
    	<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" />
    
    	<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    		<property name="jpaDialect">
    			<bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
    		</property>
    	</bean>
    
    	<tx:annotation-driven />
    
    </beans>
    My web.xml, for the fun of it:

    Code:
    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    		xmlns="http://java.sun.com/xml/ns/javaee"
    		xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    		xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
    		id="ltw-test"
    		version="3.0">
    
    	<display-name>ltw-test</display-name>
    
    	<welcome-file-list>
    		<welcome-file>index.jspx</welcome-file>
    	</welcome-file-list>
    
    	<servlet>
    		<servlet-name>spring</servlet-name>
    		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    		<load-on-startup>1</load-on-startup>
    	</servlet>
    
    	<servlet-mapping>
    		<servlet-name>spring</servlet-name>
    		<url-pattern>/spring/*</url-pattern>
    	</servlet-mapping>
    
    </web-app>
    The class I want weaved:

    Code:
    package ltw.test;
    
    import javax.persistence.PostPersist;
    
    import org.springframework.beans.factory.annotation.Autowire;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Configurable;
    import org.springframework.beans.factory.config.BeanDefinition;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.annotation.Scope;
    import org.springframework.stereotype.Component;
    
    @Configurable( value="myEntityListener" )
    @Component( "myEntityListener" ) @Scope( BeanDefinition.SCOPE_PROTOTYPE )
    public class MyEntityListener
    {
    
    	@Autowired private ApplicationContext ctx;
    
    	@PostPersist
    	public void postPersist( MyEntity e )
    	{
    		if ( this.ctx == null )
    		{
    			throw new IllegalArgumentException( "No application context" );
    		}
    	}
    
    }
    Obviously there are a few more components (The entity, JNDI data source definition, the DAO, and an interface/implementation for the MVC controller) but that's the just of it. I added -javaagent:aspectjweaver.jar to my startup. The ctx field of MyEntityListener is always null. I simply can't get this to work no matter what I try. Any help would be greatly appreciated. I know this has been done with Spring Data JPA but I'd rather find out why this setup isn't working than abandon my troubleshooting to try something else (and Spring Data JPA uses Jodatime, but that's another topic..)

    Thanks,
    Scott

    PS: The project is about 14MB in size with the libraries, I'm more than happy to attach it if desired.
    Last edited by silvaran; Jan 26th, 2012, 09:04 AM. Reason: Problem solved; added reply with details.

  • #2
    I had two issues:

    1. web.xml had version set to 3.0; it needed to be 2.5 (Tomcat class loading differences?). See https://jira.springsource.org/browse/SPR-7440

    2. For Tomcat instrumentation LTW, context:load-time-weaver needs to appear BEFORE context:component-scan. I don't have the LTW element in my above example because I was using AspectJ's weaver javaagent.

    Comment

    Working...
    X