Announcement Announcement Module
Collapse
No announcement yet.
Spring AOP & AspectJ: Help reducing startup time Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Spring AOP & AspectJ: Help reducing startup time

    [Crossposted to Spring AOP forum and AspectJ Users list]

    We have a Tomcat 6 web application that uses Spring 3.0.3 and AspectJ 1.6.10. Depending upon the hardware, startup times range from 80 seconds on our best build systems, to 2 minutes in production, to close to 4 minutes in some situations on older build systems.

    We have determined by disabling the wiring of aspects, i.e. removing <aop:aspectj-autoproxy/>, that Spring AOP is responsible for approximately 60% of the startup cost.

    Profiling with YourKit showed the vast majority of the time is beneath org.aspectj.apache.bcel.util.NonCachingClassLoader Repository. The name of the class makes me fear that we are loading and processing the same class files over and over again. However, even if a caching Repository were used, the use pattern of Repository in org.aspectj.weaver.reflect.Java15AnnotationFinder indicates that such caching would be wasted:

    bcelRepository.loadClass()
    bcelRepository.clear()

    Putting aside the non-caching nature of the Repository, we had a thought that our Pointcuts were not "good", according to Section 7.2.3.5 "Writing Good Pointcuts" of the Spring documentation. Many only had @within(<Java 1.5 Annotation>). So we added execution constraints to only look at our own classes. But this did not significantly nor sufficiently help.

    Before I ask a few questions about possible solutions, here are few more details about our application:

    - We are using Spring AOP with AspectJ annotations, i.e. @Aspect with @Component
    - We essentially have one big ApplicationContext that loads beans (450+) and Aspects (25)
    - Most beans are discovered through component-scan'ing the classpath separately for a list of 35+ packages

    Here are my questions:

    - Does the Spring AOP processing analyze beans in the context, or classes on the classpath? If it processes the beans in the context, does that include beans in parent contexts?

    - Are we simply analyzing too many beans against too many aspects? Would creating separate contexts that contain the beans for that layer, and only the aspects that apply to them improve performance sufficiently?

    - Should we attempt to convert to compile time weaving? We currently make use of Spring's @Order on several of our @Aspects, so this may not be easy, or even possible. Would this just move the cost from runtime to compile, or does it actually reduce the cost?

    - Should we try to modify AspectJ itself to have a CachingClassLoaderRepository, and fix the pattern to only clear the Repository at the end of AOP processing? Although it appears to be getting to the NonCachingClassLoaderRepository via org.springframework.aop.framework.autoproxy.Abstra ctAutoProxyCreate.postProcessAfterInitialization via org.springframework.beans.factory.support.Abstract BenFactory.getBean. So it would appear to be going a bean at a time, and there might not be a good place to clear the BCEL Repository.

    Thanks in advance for reading this far, and any time you choose to spend thinking about my problem!

    -- Josh

  • #2
    - Does the Spring AOP processing analyze beans in the context, or classes on the classpath? If it processes the beans in the context, does that include beans in parent contexts?
    Spring AOP scans only the beans in the applicationtontext it itself is defined/loaded in. So no bean scanning/processing in parent/child contexts...

    - Most beans are discovered through component-scan'ing the classpath separately for a list of 35+ packages
    Which can take quite some time when you have a large class path, all entries are checked if there is a match (so all jars etc. are scanned!)...

    - Should we attempt to convert to compile time weaving? We currently make use of Spring's @Order on several of our @Aspects, so this may not be easy, or even possible. Would this just move the cost from runtime to compile, or does it actually reduce the cost?
    Compilation would take longer startup would be faster, so it really depends on what is more important... Instead of @Order you can use @DeclarePrecedence for plain AspectJ.

    IMHO it is a matter of having a lot of beans (auto detected) which then need to be post processed to see if a proxy needs to be created (aop applied). With 450 beans even if it would take 10 ms per bean per aspect it would lead to 25 * 450 * 10ms = 112500ms to determine all that (depending on the environment, app server, jdk etc. all of that can have great influence on the performance).

    You could split the contexts and load/create different ApplicationContexts but that would probably also increase the complexity of the application.

    Another thing to consider why is it so important that the application starts fast? Isn't runtime performance more important that startup times?

    Comment

    Working...
    X