<bean id="trade"
class="org.dg.misc.Trade"
scope="prototype">
</bean>
<bean id="abstractTradingService"
class="org.dg.misc.AbstractTradingService"
lazy-init="true">
<lookup-method name="getTrade" bean="trade"/>
</bean>
I ran a performance benchmark suite to exercise 10,000 gets of the prototype bean :
BeanFactory factory = new XmlBeanFactory(
new ClassPathResource("trade_context.xml"));
ITradingService ts = (ITradingService) factory.getBean(
"abstractTradingService");
StopWatch stopWatch = new StopWatch();
stopWatch.start("lookupDemo");
for (int x = 0; x < 10000; x++) {
ITrade trade = ts.getTrade();
trade.calculateValue(null, null);
}
stopWatch.stop();
System.out.println("10000 gets took " +
stopWatch.getTotalTimeMillis() + " ms");
Spring 2.0.2 reported a timing of 359 milliseconds for the 10,000 gets. I performed the same exercise in Guice with a similar configuration :
public class TradeModule extends AbstractModule {
@Override
protected void configure() {
bind(ITrade.class).to(Trade.class);
bind(ITradingService.class).to(TradingService.class).in(Scopes.SINGLETON);
}
}
and the corresponding test harness :
Injector injector = Guice.createInjector(new TradeModule());
long start = System.currentTimeMillis();
for(int i=0; i < 10000; ++i) {
injector.getInstance(ITradingService.class).doTrade(injector.getInstance(ITrade.class));
}
long stop = System.currentTimeMillis();
System.out.println("10000 gets took " + (stop - start) + " ms");
For this exercise of 10,000 gets, Guice reported a timing of staggering 31 milliseconds.
Then a couple of days back Juergen Hoeller posted in the release news for Spring 2.0.4, that repeated creation of prototype bean instances has improved up to 12 times faster in this release. I decided to run the benchmark once again after a drop-in replacement of 2.0.2 jars by 2.0.4 ones. And voila ! Indeed there is a significant improvement in the figures. The same test harness now takes 109 milliseconds on the 2.0.4 jars. Looking at the changelog, you will notice several lineitems that have been addressed as part of improving bean instantiation timings.
This is what competition does even for the best .. Keep it up Spring guys ! Spring rocks !
Updated: Have a look at the comments by Bob and the followups for some more staggering benchmark results.
6 comments:
Creating a competing product in a space where there already is a clear top dog is "crazy" :)
As long as spring stucks to Java 1.3 compatibiltiy, it will keep sucking.
@A.A.A. I respectfully disagree. Spring can support 1.3 and still support plenty of JDK 5.0 features :)
Your Guice example actually isn't equivalent to your Spring example. Based on the code you've provided, it will be more fair to replace ITradingService with Provider<ITrade> in the Guice example.
Your configuration code should look like this:
public class TradeModule extends AbstractModule {
@Override
protected void configure() {
bind(ITrade.class).to(Trade.class);
}
}
And the test harness should look like this:
Injector injector = Guice.createInjector(new TradeModule());
Provider<ITrade> tradeProvider
= injector.getProvider(ITrade.class);
long start = System.currentTimeMillis();
for(int i=0; i < 10000; ++i) {
ITrade trade = tradeProvider.get();
trade.calculateValue(null, null);
}
long stop = System.currentTimeMillis();
System.out.println("10000 gets took " + (stop - start) + " ms");
If you want to keep ITradingService around, you can just inject Provider<Trade> into it.
Please let us know the new results.
Hi Bob -
Thanks a lot for your suggestions. I made the following changes :
public class TradingService implements ITradingService {
@Inject
private Provider<ITrade> tradeProvider;
public ITrade getTrade() {
return tradeProvider.get();
}
// ..
}
and the test harness ..
Injector injector = Guice.createInjector(new TradeModule());
ITradingService ts = injector.getInstance(ITradingService.class);
long start = System.currentTimeMillis();
for(int i=0; i < 10000; ++i) {
ITrade trade = ts.getTrade();
trade.calculateValue(null, null);
}
long stop = System.currentTimeMillis();
System.out.println("10000 gets took " + (stop - start) + " ms");
and guess what happened !! The time reported is 16 ms. Previously it was 31 ms. But I realized that this will be a more proper benchmark than the previous one. Thanks for the suggestion and thanks a ton for Guice.
Just one point I would like to clarify from you - what is your opinion regarding annotations like @Inject coming from an external framework (I mean non-JDK) being inserted into business class ?
Thanks.
- Debasish
Early adopters depend on 3rd party frameworks all the time. Before JPA, we depended on Hibernate (you still have to to some extent). There's Joda time. Quartz. Log4j. With Spring, you write lots of XML which is Spring-specific.
Post a Comment