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.
Filed under: Java
There are several reasons why I prefer not to use SPRING.
1. Spring configuration is bloated.
My team develop enterprise application using Dependency Injection framework. There are more than 1500 classes in that project, and separated to more than 11 modules.To my experience in a real world, “we made service object less then the object who depend on that service”. If we use spring framework when we made 1000 actions who depend in 100 service, it means we have to make configuration on 1000 bean that depend on 100 service. The configuration getting worst if the actions continue growing in numbers, we must very extra carefull when we want to refactor something, we dont want to break existing code. You might start thinkin using autowire by type … no that would be a bad idea. Then … why not using autowire by name, … that sound silly what if we have different name in configuration for different object, well i guess thats gonna be another long nite at the office.
2. Putting configuration into XML is painful.
XML configuration is painful, the context painful is not something concerning how top coder you are, but more on maintenance. If you have 1000 actions then you got to be very aware what and where the configuration taken place in XML, you should have an eagle eye, you must not forget to use tools feature find and replace to change the xml configuration. Otherwise the application will blowup when going on production.
3. You loose Java Strong Type Checking if using XML configuration
When you start using XML configuration, you will loose the power of java. When you lucky the object that you inject into the bean is not what the bean wanted. You have to wait until Spring Start Running and start checking the dependency, at that time you realize you made a silly mistake. Ouchh ….
Some Configuration not using XML but in Java class, in GUICE you use module, If we want flexibility, we still can achieved by separate the business logic jar into another archive, and in the core jar we just put Class.forname(“the module class”). Thats all
4. Spring is not light weight container.
Unfortunately spring is not light weight anymore. Today Spring performance is not the fastest anymore, there are more lightweight container exist out there where the performance is better.
5. Spring is a Container that promise us to build loosely coupled application.
Spring is a container that just promise us to build loosely coupled technology, spring does not really concern that much about tightly coupled. I’m very sure that once we use spring lib other than spring-core.jar that means our application cannot live without spring.
Filed under: Java
I was invited by Java User Group Indonesia as a speaker in regular monthly meeting held at Sun Microsystems Indonesia on June 30th 07. This time topic is GUICE. In contrary, two years ago at the same place, I speak about SPRING framework. At that time not much people are aware about spring, today the spring community in Indonesia is growing wide and here we go again, I’m standing against the main stream.
I made some example using GUICE to create web blog application using Struts 2 – Guice – JPA hibernate. To my Experience GUICE is very simple and learning curve is not as much as spring. Nothing can compare the beauty of Module and binder in GUICE, not even the Spring Java Config can do that.
The Presentation covered from simple hello world to advance GUICE such as provider, scope – “how to create custom scope” , aspect using AOP Alliance and create declarative transaction using aspect.
I made some example how we can externalize module into properties or xml, however this is not good, since we will loose the power of strong type checking in JAVA.
I recommend friends how to modularize the GUICE module, we can seperate GUICE module into different JAR, and by using Class.forname we can have the module runnin right away. We treat the module as plugins.
So …. go a head , have some GUICE.!!