[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:
Putting aside the non-caching nature of the Repository, we had a thought that our Pointcuts were not "good", according to Section 184.108.40.206 "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!