Recently I was debugging an application where it was taking a really long time to load spring application context. The application server folks were complaining because they were getting paged and it was really making development painful as integration test were exceeding over 3+ minutes. We are dealing with lots of legacy xml configuration based modules and are moving to java config but it feels like a big pipe dream unless we were able to write a semi-automated script to convert applicationContext.xml to java config files.
Most enterprises application start up times aren't a concern but I have run two situations in the past where it matters. First was running a spring based application in google app engine due to app Engine frontend instances are dynamically scaled. What this means is if your load reaches a threshold it will spin up a new instances and if it takes a long time for it to ready to serve you could add additional latency for users. The second case was when running in a batch environment where again the application wasn't in a load once and run forever environment.
I thought it would be helpful to share what I experienced and others I found were breaking down the application start up times.
Jar dependencies and import resources
Our modules are built to be run independent of any other resources meaning bring in what you need to the applicationContext.xml and you are on your way. There is a slight problem if you have a complex interrelated modules that depend on one another that use
. For example:
jar.jar * applicationContext.xml **
jar2.jar * applicationContext.xml **
What happens is the config.xml will be loaded twice and there isn't a way for it to remember.
Change component scans to be specific
Component scanning takes a long time especially if you have unnecessary scans by user error or if you aren't scanning specific packages. For instance, if you have a generic packages use throughout your modules such as com.levelup.example. Then you have multiple nodes after example like com.levelup.example.io, com.levelup.example.strings, com.levelup.example.arrays and com.levelup.example.collections. If you are importing all the jars with those packages and if you are scanning com.levelup.example you will be scanning for all classes across that node. Try to limit and make sure each jar is only scanning for what it needs.
Do not use wild car class path scanning
If you are familiar with ibatis you define SqlMapConfig that contain sql statements, object relational mapping, etc and you typically only define a single instance of a SqlMapClientFactoryBean or SqlSessionFactoryBean per applications. In the instance where you have lots of modules you require consumers to pull all of these together. One way to do this is scanning the entire class path. When you do this be sure to be specific. Instead of this classpath:SqlMapConfig.xml use classpath:**/ibatis/SqlMapConfig.xml as it will reduce the total time it takes/
We used ibatis but this really could go for any files necessary that you classpath scan for.
Developer education
How in the hell has any developer tolerated running builds that have taken so long? Why in the world was this issue not brought up prior til it is bringing applications to their knees. We can't expect all newbies to know or every SR to review every piece of code. What we do know is as you incrementing your build process if it is significantly adding time to your cycle, raise the flag people!
Other notables
- You could using lazy-init= true where possible. I personally don't think this is at all feasible.
- Does every class need to be a bean? Often newbies don't understand when to add @Component so by default it is added everywhere. If you don't need it don't add it.
- turn off bean validation. There is ways to do this but ideal. I would expect that you should be able to set a system property in production where it would automatically disable xsd validation but unfortunately not.