Announcement Announcement Module
Collapse
No announcement yet.
AOP & Junit - performance questions Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • AOP & Junit - performance questions

    I have recently started integrating AspectJ into my project via @Configurable. Seems like an excellent way to add dependency injection to objects created by Hibernate. Everything is working well - I'm actually quite impressed! Thanks to everyone who has contributed to these projects.

    My problem comes with performance of LTW. I understand that the performance hit is only taken once on load time, but this doesn't seem to work will with the theme of Junit, which we like to run continuously throughout the day.

    A single JUnit test that used to take less than 8 seconds to run now takes 30+ seconds. Multiply this by all the tests in our application, and suddenly this makes running continuous unit tests extremely difficult.

    Would I be better off disabling LTW and doing everything at compile time with Ant tasks? What about for testing within Eclipse? It seems like the compile time approach that would be a preferred solution, but there doesn't seem to be much discussion about this on the Spring forums, which is why I am questioning the approach.

    As for my application configuration, I only have a handful of classes that are currently @Configurable. They are specified in my aop.xml file as follows:

    Code:
    <include within="com.foo.bar..*"/>
    I enabled -showWeaveInfo to verify the statement works, and indeed, the logging changes between:

    Code:
    INFO AspectJ Weaver:55 - [AspectJ] not weaving 'org/springframework/beans/factory/CannotLoadBeanClassException'
    
    INFO AspectJ Weaver:55 - [AspectJ] weaving 'org/springframework/core/io/Resource'
    so it looks like that works, but it still doesn't help the speed problem (timing tests are without logging, of course)

    I am currently using Spring 2.0.1 and aspectj 1.5.3. I tried with the latest Spring nightly as suggested in http://opensource.atlassian.com/proj...rowse/SPR-2703 with no change, but I believe they were discussing a different issue. I'm running OS X on a G5 with 1.5GB of RAM.

    Ideally I'd like to run my unit tests in eclipse while developing and with Ant while regression testing. I've seen a bunch of posts here and there discussing LTW performance, but never with any resolutions or suggestions.

    Any thoughts on best practices and how to speed things up?

  • #2
    My solution

    I'll post what I have working currently with links to the research that I did along the way for posterity.

    I definitely wanted to get away from LTW. My understanding is that many people in the Spring community like it because it doesn't change you build process much at all, which I'll admit is a strong selling point. The problem I had was the performance. Couldn't deal with 6 minutes to run 60 junit tests.

    This thread has some more notes on the topic:
    http://forum.springframework.org/showthread.php?t=31724
    plus a link to a aspectj mailing list discussion on the pros and cons of LTW:
    http://dev.eclipse.org/mhonarc/lists.../msg07098.html

    I then spent a long while struggling through to Eclipse/AspectJ documentation, specifically for the Ant tasks:
    http://www.eclipse.org/aspectj/doc/r.../antTasks.html

    I found these pretty unhelpful, especially since there were so many different ways to approach the problem (acj, iajc, javac+adaptor,etc).

    From some sample code on the aforementioned post and some guesswork (where's the ant task specification???), I finally eked out the following:

    Code:
    <iajc destdir="${class.dir}" aspectPathRef="aspectPath"
                source="1.5" target="1.5" showWeaveInfo="true">
    	<classpath>
    		<path>
    			<fileset  dir="${lib.dir}" />
    		</path>
    	</classpath>
    	<src path="${src.java.dir}" />
    	<include name="**/*.java" />						
    	<exclude name="**/Bad*.java" />
    </iajc>
    In order to get the ant task to work, you're going to need aspectjtools.jar on your ant classpath. You can dump it in your $ANT_HOME/lib folder, or specify it in the build script (didn't figure out how to do the latter, although it's probably the better solution since there's no environment dependency).

    Oh, and to get the aspectjtools.jar, you should download and install aspectj from http://www.eclipse.org/aspectj/downloads.php
    The jar is executable and will install when you run it. The lib directory of that install has the .jar files you need for Ant.

    I replaced my Ant "compile" target that calls Javac with one that calls iajc as above. I don't really know the ramifications of doing this. What is the relationship between iajc and javac? Am I completely dependent on this compiler now? What if I want Jikes or something like that? Comments here are appreciated.

    At this point, most things seemed to be working well. Although I ran into a strange problem with some unrelated code. Specifically, I have some Hibernate classes that are annotated @Transactional (See Spring reference docs: http://www.springframework.org/docs/...ve-annotations)
    I was able to set this up not realizing it had much of anything to do with AOP by declaring the beans specficied in the doc:

    Code:
    <tx:annotation-driven transaction-manager="txManager"/>
    <bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    	<property name="sessionFactory" ref="HibernateSessionFactory"/>
    </bean>
    I have had that code working well for the past few weeks without any problems. However changing to the aspectj compiler caused problems. Specifically, it caused my application to break with the following strange exception:
    Code:
    java.lang.NullPointerException
            at org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:257)
            at org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:216)
            at org.springframework.transaction.aspectj.AbstractTransactionAspect.ajc$before$org_springframework_transaction_aspectj_AbstractTransactionAspect$1$2a73e96c(AbstractTransactionAspect.aj:64)
    After a lot of searching, I came across this thread:
    http://forum.springframework.org/showthread.php?t=28649

    which told me to add the following:
    Code:
    <bean class="org.springframework.transaction.aspectj.AnnotationTransactionAspect"
                factory-method="aspectOf">
            <property name="transactionManager" ref="txManager"/>
    </bean>
    I probably should have guessed that

    After that, everything ran automagically. My 60 tests now complete 100% in just over 1 minute and everything is right with the world. Although I'm not quite sure what that last bean does

    So hopefully this long winded post will save someone a little time & effort. Hope it helps, and critiques and comments are most welcome, especially thoughts about the compiler.

    Comment


    • #3
      Getting the above working in Eclipse IDE

      Just another followup to the above. Everything I did worked great, except trying to start my server from inside Eclipse didn't work properly. Obviously because Eclipse uses a regular javac compiler and not an aspectj one.

      I installed the AspectJ Eclipse plugin (AJDT) from http://www.eclipse.org/ajdt/

      After that, it was very unclear how to get the IDE to actually use the new compiler. After some searching, it turns out you can right click on the project in the package explorer and convert it to an AspectJ project (it was previously a Java project). Note that you can change it back by right-clicking again and choosing "Remove AspectJ Capabilities" menu.

      Now the correct compiler was being used (verified by comparing bytes of the .class files before and after with the ones I created in Ant). But my application still didn't behave correctly (specifically, the @Configurable class wasn't getting @configured properly by Spring, resulting in no DI and null member variables). NB: The Project->Properties->Builders tab now should have an AspectJ Builder instead of a Java builder. You should be able to verify this way too.

      The problem was that the Aspectj builder didn't know about the spring-aspects.jar file that has the definitions of the @Configurable aspect. It's not sufficient ot have it on the classpath - it has to be in the AspectPath (see the Ant build.xml above for how it's declared).

      After lots of clicking, I found the project->properties->AspectJ Build->Aspect Path menu. I added the spring-aspects.jar file. and voila! Magic!

      NB I had to manually clean out all the files from my bin (eclipse build) directory before building. They weren't automatically built fresh the first time.

      Hope this helps someone out.

      PS I still don't know what side effects migrating to the AspectJ compiler for the entire project might have that could bite me later. Any thoughts?

      Comment


      • #4
        Someone offline asked me how I originally got LTW working. In addition to the code and context changes, I added the following command line arguments my java call:

        Code:
        -javaagent:lib/aspectjweaver.jar
        (lib could be found is on my classpath, of course)

        Comment


        • #5
          Thanks

          Hi hoist2k

          Thanks for posting the solution, found the same performance problem with LTW. Also had a problem with mocking LTW concrete classes with easy mock class extensions. Good to see someone posts solution when they find it even though no response to original post.

          Comment

          Working...
          X