javamavenaopspring-aopcompile-time-weaving

Why doesn't AspectJ compile-time weaving of Spring's @Configurable work?


Update 5: I've downloaded the latest Spring ToolsSuite IDE based on the latest Eclipse. When I import my project as a Maven project, Eclipse/STS appears to use the Maven goals for building my project. This means AspectJ finally works correctly in Eclipse.

Update 4: I have ended up just using Maven + AspectJ plugin for compile-time weaving, effectively bypassing Eclipse's mechanism.

Update 3: It seems AspectJ's Eclipse plug-in breaks Eclipse's ability to correctly Publish to Tomcat. Only by removing the AspectJ capability on a project can I get it to properly Publish again. Very annoying.

Update 2: I have this now working in Eclipse. It makes me very uncomfortable to say this, but I have no idea how I got it working from either Eclipse or Maven builds. It appears to be a compile issue rather than a run-time issue.

Update 1: It appears I've gotten this to work via Maven builds, but I have no idea how. Eclipse still doesn't work. The only thing I changed in the pom.xml was adding these (insignificant?) configuration parameters:

<source>1.6</source>
<complianceLevel>1.6</complianceLevel>
<verbose>true</verbose>
<showWeaveInfo>true</showWeaveInfo>
<outxml>true</outxml>

I'm actually worried that I have a repeat of this problem, where everything works inconsistently. I will keep this question updated as I learn more.

With regards to Eclipse, I made some progress by taking the binary aspects I wish to weave - in this case spring-aspects.jar - and copying it out of my classpath. I then add this now external jar to my Aspect Path. After doing this, Eclipse properly shows me AspectJ markers in my code. It's annoying that I can't just leave spring-aspects.jar in my Java Build Path which is maintained by Maven for me via the Maven plug-in. For some reason, however, the AspectJ plug-in doesn't see the binary aspects unless they're explicitly added to the Aspect Path.


Original Post: @Configurable is a Spring annotation that allows dependencies to be injected into objects instantiated external to Spring (for example, by Hibernate or some Factory class).

I was using this annotation previously with load-time weaving and it mostly worked. Occasionally I would boot up and nothing would get injected. This issue spawned this StackOverflow question. There weren't many answers, but most suggested that I try compile-time weaving instead due to greater reliability.

I installed the AspectJ plug-in for Eclipse and Maven. Both of these produce what appears to be properly compiled classes. I've opened up one of the classes in a text editor before AspectJ compilation and found no references to AspectJ. I opened it up after AspectJ compilation and both Eclipse and Maven generated versions have a reference to org.aspectj.weaver.MethodDeclarationLineNumber. This is why I assume it's being properly compiled. The problem is that once deployed, no dependencies get injected.

My Spring applicationContext.xml does include the following:

    <context:spring-configured />

    <context:component-scan base-package="com.myapp" />

Is the above all that's needed for classes marked @Configurable to have DI done? During the conversion from load-time weaving to compile-time weaving, I removed META-INF/aop.xml, <context:load-time-weaver /> from my applicationContext.xml, and Spring's Tomcat weaver from my context.xml.

How can I investigate this problem further? What are possible causes?


Solution

  • It works for us on maven using compile time weaving, try adding the following plugins:

    <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <configuration>
        <compilerVersion>1.6</compilerVersion>
        <fork>true</fork>
        <source>1.6</source>
        <target>1.6</target>
    </configuration>
    </plugin>
    
    <plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>aspectj-maven-plugin</artifactId>
    <executions>
        <execution>
            <id>compile</id>
            <configuration>
                <source>1.6</source>
                <target>1.6</target>
                <verbose>false</verbose>
                <outxml>true</outxml>
                <aspectLibraries>
                    <aspectLibrary>
                        <groupId>org.springframework</groupId>
                        <artifactId>spring-aspects</artifactId>
                    </aspectLibrary>
                </aspectLibraries>
            </configuration>
            <goals>
                <goal>compile</goal>
            </goals>
        </execution>
        <execution>
            <id>test-compile</id>
            <configuration>
                <source>1.6</source>
                <target>1.6</target>
                <verbose>false</verbose>
                <aspectLibraries>
                    <aspectLibrary>
                        <groupId>org.springframework</groupId>
                        <artifactId>spring-aspects</artifactId>
                    </aspectLibrary>
                </aspectLibraries>
            </configuration>
            <goals>
                <goal>test-compile</goal>
            </goals>
        </execution>
    </executions>
    <dependencies>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.6.4</version>
        </dependency>
    </dependencies>
    </plugin>
    

    Its done as two separate execution steps to allow you to add different aspect libraries for unit testing and compilation.

    You'll also need the following dependency added for the spring-aspects library:

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <scope>compile</scope>
        </dependency>