The Pathfinder


Google GUICE 1000% faster than Spring !
July 5, 2007, 7:47 am
Filed under: Java

Believe it or not, Google Guice is 1000% faster than Spring. This google product wins every aspect of performance compare to Spring. From load module/context to resolve binding object, Guice is the absolute winner.I personally benchmark this two popular Dependency Injection framework myself. And I have made some scenario as if the real world application of the both framework work.

In a real world there are framework client that require objects to be injected. Typically these client performing action, receive request from actor and process the request and send the result back to the actor. These client are instance of actions in struts or webwork, or even a servlet. These action does not contains business logic, usually we put some business logic in a facade/service/manager, these facade are the instance that will injected into the client by framework.

Facade instance are managed by the framework, usually the perform logic for ex. “read user by name from access object” and do something with it. That means facade instance required dependency of Data Access Object service. Typically these service could be singleton or even prototype. It depends the architecture we built.

Data Access Objects are another instance that managed by the framework. Typically this object performing actions to access the persistent framework session, or entity manager.

In a real world, the dependency of an objects can be very complex. As your application grows, the need of an object to be able to communicate one and another or switching old object to new object are managed by the DI framework and configurable.
Based on above scenario, I made benchmark of two popular framework Google Guice and Spring.

(MainService)
          |_______ServiceOne
                                 |________ServiceFour
                                 |________ServiceFive
                                 |________ServiceSix
          |_______ServiceTwo
                                 |________ServiceSeven
                                 |________ServiceEight
                                 |________ServiceNine
          |_______ServiceThree
                                 |________ServiceTen
                                 |________ServiceEleven
                                 |________ServiceTwelve

MainService is the Facade, ServiceOne, ServiceTwo, ServiceThree are the manager, and ServiceFour until ServiceTwelve are the DAOs.
Typically as the application grows the dependency hierarchy could be more deeper and complex. But for the sake of benchmark ill keep it simple.

As I have mention before the service can be singleton or prototype. It depends on the architecture, so I will test in both fashion, in Singleton and prototype.

To give more objective on both framework, I will test the framework performance starting from one clients , and continues to 10,100,10000 client calling for request to be binded their dependency by the framework.

And also to make sure that the client is actually get the object that they want, the client will call method in service so the main service will the objects that depends on. This could be a mechanism to validate is the framework works.

The Service

public interface Service {
	public void doService();
	public Date getCreatedOn();
}

The service contains the information on when the service object is being created and method doService to perform service functionality.
All the implementation class from MainService to ServiceTwelve is implementing Service interface.

The StopWatch

public class StopWatch {
	private static final List serviceInstances = new LinkedList();

	/**
	 * @return the serviceInstances
	 */
	public List getServiceInstances() {
		return serviceInstances;
	}

	public static void recordInstance(Service service){
		serviceInstances.add(service);
	}

	public static void clear(){
		serviceInstances.clear();
	}

	public static long averageInstanceCreationInMs(){
		long total = 0;
		Date date = null;
		for (Service service : serviceInstances) {
			if(date == null){
				date = service.getCreatedOn();
			}else{
				total = total + (service.getCreatedOn().getTime() - date.getTime());
			}
		}
		return total/serviceInstances.size();
	}

	public static int totalInstance() {
		return serviceInstances.size();
	}
}

The stop watch is an object that will record the service instantiation time, and calculate the lag time between one creation of service object and another. By Counting this service creation time, and average the time, then we will find how much does the framework actually perform to binding object and inject it to the host in millisecond.

The Configuration

I separate configuration into two different files, first is the configuration for dependency that the objects are prototype and the other is singleton.

Guice Module Prototype 
public class GuiceModulePrototype extends AbstractModule{

	@Override
	protected void configure() {
		bind(Service.class).annotatedWith(Client.ClientService.class).to(MainService.class);
		bind(Service.class).annotatedWith(MainService.ServiceOne.class).to(ServiceOne.class);
		bind(Service.class).annotatedWith(MainService.ServiceTwo.class).to(ServiceTwo.class);
		bind(Service.class).annotatedWith(MainService.ServiceThree.class).to(ServiceThree.class);
		bind(Service.class).annotatedWith(ServiceOne.ServiceFour.class).to(ServiceFour.class);
		bind(Service.class).annotatedWith(ServiceOne.ServiceFive.class).to(ServiceFive.class);
		bind(Service.class).annotatedWith(ServiceOne.ServiceSix.class).to(ServiceSix.class);
		bind(Service.class).annotatedWith(ServiceTwo.ServiceSeven.class).to(ServiceSeven.class);
		bind(Service.class).annotatedWith(ServiceTwo.ServiceEight.class).to(ServiceEight.class);
		bind(Service.class).annotatedWith(ServiceTwo.ServiceNine.class).to(ServiceNine.class);
		bind(Service.class).annotatedWith(ServiceThree.ServiceTen.class).to(ServiceTen.class);
		bind(Service.class).annotatedWith(ServiceThree.ServiceEleven.class).to(ServiceEleven.class);
		bind(Service.class).annotatedWith(ServiceThree.ServiceTwelve.class).to(ServiceTwelve.class);
	}

}
Guice Module Singleton 
public class GuiceModuleSingleton extends AbstractModule{

	@Override
	protected void configure() {
	bind(Service.class).annotatedWith(Client.ClientService.class).to(MainService.class).in(Scopes.SINGLETON);
	bind(Service.class).annotatedWith(MainService.ServiceOne.class).to(ServiceOne.class).in(Scopes.SINGLETON);
        bind(Service.class).annotatedWith(MainService.ServiceTwo.class).to(ServiceTwo.class).in(Scopes.SINGLETON);
	bind(Service.class).annotatedWith(MainService.ServiceThree.class).to(ServiceThree.class).in(Scopes.SINGLETON);
        bind(Service.class).annotatedWith(ServiceOne.ServiceFour.class).to(ServiceFour.class).in(Scopes.SINGLETON);
	bind(Service.class).annotatedWith(ServiceOne.ServiceFive.class).to(ServiceFive.class).in(Scopes.SINGLETON);
        bind(Service.class).annotatedWith(ServiceOne.ServiceSix.class).to(ServiceSix.class).in(Scopes.SINGLETON);
	bind(Service.class).annotatedWith(ServiceTwo.ServiceSeven.class).to(ServiceSeven.class).in(Scopes.SINGLETON);
        bind(Service.class).annotatedWith(ServiceTwo.ServiceEight.class).to(ServiceEight.class).in(Scopes.SINGLETON);
	bind(Service.class).annotatedWith(ServiceTwo.ServiceNine.class).to(ServiceNine.class).in(Scopes.SINGLETON);
        bind(Service.class).annotatedWith(ServiceThree.ServiceTen.class).to(ServiceTen.class).in(Scopes.SINGLETON);
	....
	}
}

spring-module-singleton.xml

<beans>
<bean id="mainService" class="guice.comparison.service.MainService" >
	<property name="serviceOne">
		<ref bean="serviceOne"/>
	</property>
	<property name="serviceTwo">
		<ref bean="serviceTwo"/>
	</property>
	<property name="serviceThree">
		<ref bean="serviceThree"/>
	</property>
</bean>

<bean id="serviceOne" class="guice.comparison.service.ServiceOne" >
	<property name="serviceFour">
		<ref bean="serviceFour"/>
	</property>
.....
</beans> 
spring-module-prototype.xml

<beans>
<bean id="mainService" class="guice.comparison.service.MainService" singleton="false">
	<property name="serviceOne">
		<ref bean="serviceOne"/>
	</property>
	<property name="serviceTwo">
		<ref bean="serviceTwo"/>
	</property>
	<property name="serviceThree">
		<ref bean="serviceThree"/>
	</property>
</bean>

<bean id="serviceOne" class="guice.comparison.service.ServiceOne" singleton="false">
	<property name="serviceFour">
		<ref bean="serviceFour"/>
	</property>
....
</bean>

spring-module-client.xml

<beans>
<bean name="0" class="guice.comparison.Client" singleton="false">
<property name="service"><ref bean="mainService"/></property>
<property name="name"><value>0</value></property>
</bean>
....
....
</beans>

Above are the configuration for the spring. For Spring we still do need to create a context for clients, because in spring the client it self must be configured so the spring can inject the client dependency object.

To make it dynamic I made a simple class to create an spring xml configuration. That will automatically create xml client of n beans. “can u imagine creating xml configuration of 10000 bean by hand :( that can take days to make sure everything is in its place, Imagine you create 10000 actions that depend 13 service that means you configuration actions bloated !!”


The Main

public static void main(String[] args) throws IOException{
		boolean singleton = false;
		boolean callMethod = true;
			int client = 1;
			StopWatch.clear();
			long loadModule = springClientRequest(client,singleton,callMethod);
			System.out.println("Springt "+client+"t"+singleton+"t"+callMethod+"t"+StopWatch.averageInstanceCreationInMs()+"t"+StopWatch.totalInstance()+"t"+loadModule);

			StopWatch.clear();
			loadModule = guiceClientRequest(client,singleton,callMethod);
			System.out.println("Guicet "+client+"t"+singleton+"t"+callMethod+"t"+StopWatch.averageInstanceCreationInMs()+"t"+StopWatch.totalInstance()+"t"+loadModule);
	}

The main method will perform to create framework modules and start benchmark.

For spring framework, the client will be pulled from the spring context, as the behavior of spring where the client it self is being managed by the container.

For guice framework, the client will be instantiated and injected into the injector, and then injector bind all the object that client needs.

The result as following

#C number of client
S : Service are singleton
C : Method doPerfom is called
I : Instance created in framework
T : Average time of framework binding object into bean in ms
M : module/context startup time in ms

	#C	S	C	I	T	M
spring	1	y	y	13	34	601
guice	1	y	y	13	0	407
spring	10	y	y	13	26	607
guice	10	y	y	13	0	393
spring	100	y	y	13	28	768
guice	100	y	y	13	0	456
spring	1000	y	y	13	53	1300
guice	1000	y	y	13	0	492
spring	10000	y	y	13	35	3910
guice	10000	y	y	13	0	417 

spring	1	y	n	13	20	528
guice	1	y	n	13	0	457
spring	10	y	n	13	25	530
guice	10	y	n	13	0	392
spring	100	y	n	13	21	744
guice	100	y	n	13	0	537
spring	1000	y	n	13	34	1445
guice	1000	y	n	13	0	591
spring	10000	y	n	13	34	3819
guice	10000	y	n	13	0	401 

spring	1	n	n	13	35	660
guice	1	n	n	13	0	419
spring	10	n	n	130	88	612
guice	10	n	n	130	0	406
spring	100	n	n	1300	221	708
guice	100	n	n	1300	6	415
spring	1000	n	n	13000	877	1243
guice	1000	n	n	13000	55	386
spring	10000	n	n	130000	3858	3765
guice	10000	n	n	130000	202	400 

spring	1	n	y	13	31	567
guice	1	n	y	13	0	393
spring	10	n	y	130	67	564
guice	10	n	y	130	1	407
spring	100	n	y	1300	223	693
guice	100	n	y	1300	7	435
spring	1000	n	y	13000	957	1259
guice	1000	n	y	13000	43	424
spring	10000	n	y	130000	2931	3859
guice	10000	n	y	130000	208	405

As we can see the average time that both framework perform when injecting the bean to the client, GUICE is far more faster than Spring. In 10000 bean of client that requested to be injected of object which type is Proxy(not singleton), GUICE shows its superior where the performance is 1000% percent faster than Spring !

In Singleton service that will injected into client, GUICE has outstanding performance where almost more than 50 times faster than spring.

The results really remarkable, as we can see, the Spring load time is getting higher as the configuration getting big. In contrary Guice is relatively constant, I set Guice Stage in Production so I was expecting GUICE will perform slower, then I was wrong, GUICE does not have problems with bigger client request.

If we realize this is the benefit of GUICE architecture, GUICE does not manage all the client instance, GUICE only inject what instance that client need.

In the end, GUICE architecture has given remarkable new horizon in the new breed of ultra light weight container.

sourcecode available here


10 Comments so far
Leave a comment

You’re data is so valid. Thanks for doing the work and giving us this perspective. You’re the man rif

Comment by joshua

Thanks Joshua :)

Cheers

Comment by gorif

You seem to be hammering on the xml configuration, but have you ever taken a look at the other configuration possibilities of Spring? I guess not because all your posts are about XML.

I would like to see a comparison between Spring xml, java config, annotations.

Also your comparison isn’t completly fair, Spring does more then simply inject beans it also provides the beans with a (hefty?) lifecycle and lifecycle operations (as you stated yourself). Guice doesn’t have any of those so yes it is faster because is doesn’t have that overhead.

Comment by Marten Deinum

@Marten

Spring does indeed have lifecycle management (though nothing hefty–see PicoContainer if you want sophisticated lifecycle).

However I cannot see where gorif is invoking any lifecycle methods on his spring beans. They are on equal footing.

Nonetheless I am skeptical of micro-benches like this. I wonder how much clock time is spent parsing xml and in the gc. Bob Lee’s bench is somewhat better.

But lifecycle or not, 1000x or 10x, whatever other factors–there is absolutely no doubt that guice is *significantly* faster than spring in both bootstrap and per-service-injection.

Comment by Dhanji

@Marten
As I have mention before, I try to make the comparison as is in the real world. Most people do it by using xml configuration not to mention I had several project developed using spring too :)

Yes, Spring does provide lifecycle once we used application context and capability trigger event into the context. But, have you see the example code, it is pure beanFactory, im not using applicationcontext.

Comment by gorif

[...] After that, Guice (1.0) seems to be only 10 times faster than Spring (2.0.6). Have a look at another performance test here. [...]

Pingback by Comparison between Guice, PicoContainer and Spring

ora ngerti gor!!! pake bahasa GSM/UMTS siy hehehe
keep the good work Pak!

Comment by kakayanu

duh..
ni pada ngebahas apaan toh gor?
asli gue kagak ngerti sama sekali..
pakai english pulak..

Comment by andyan

ONLINE – DRUGSTORE!
PRICES of ALL MEDICINES!

FIND THAT NECESSARY…
VIAGRA, CIALIS, PHENTERMINE, SOMA… and other pills!

Welcome please: pills-prices.blogspot.com

NEW INFORMATION ABOUT PAYDAY LOANS!

Welcome please: payday-d-loans.blogspot.com

GOOD LUCK!

Comment by karpMaitari




Leave a comment
Line and paragraph breaks automatic, e-mail address never displayed, HTML allowed: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <pre> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>