DI: Comparing Spring vs Guice

With Examples


22 Oct 2016 View Comments
#dependency #injection #DI #spring #google #guice #java #computer

What is a Dependency Injection? Why do we need it?

Last time I wrote about design patterns on how we can create objects in different ways. Here is another way of creating an object, which is called Dependency Injection. Simply put, dependency is being injected from outside (container). There are 2 of the most popular ways to inject objects. One is to use Spring Framework, the other would be Guice created by Google. Let’s talk about these 2 and how they compare to traditional object creation.

  1. Spring Framework (aka Spring MVC)
  • Constructor Injection
  • Setter Injection
  • Interface Injection

I will not go through all of them above. I will explain the Injection via Constructor method. First, you need to load maven dependencies, you may not need the all of these dependencies but they are here more for reference purpose:

   <dependency>
       <groupId>org.springframework</groupId>
       <artifactId>spring-core</artifactId>
       <version>${spring.version}</version>
   </dependency>
   <dependency>
       <groupId>org.springframework</groupId>
       <artifactId>spring-context</artifactId>
       <version>${spring.version}</version>
   </dependency>

We make a simple class with Constructor:

package org.calvin.beans;

public class SpringTest {

    private final fileManager;
    public void SpringTest(FileManager fileManager) {
       this.fileManager = fileManager;
    }
}

FileManager.java:

package org.calvin.beans; 

public class FileManager {
   private File = new File();
   public File getDirectory(final String directory) throws IOException {
      ... code ...
   }

   ... code ...
}

And then we need beans applicationContext.xml:

After you have them ready, prepare your bean xml.

<?xml version="1.0" encoding="UTF-8"?>
 <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:context="http://www.springframework.org/schema/context"
        xmlns:lang="http://www.springframework.org/schema/lang"
        xmlns:util="http://www.springframework.org/schema/util"
        xmlns:aop="http://www.springframework.org/schema/aop"
        xmlns:tx="http://www.springframework.org/schema/tx"
        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
           http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-2.5.xsd
           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
           http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd
           http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
 
    <bean id="fileManager" class="org.calvin.beans.FileManager /> 
    <bean id="springTest" class="org.calvin.beans.SpringTest" />
        <constructor-arg ref="fileManager"/>
    </bean>
</beans>

Then finally here is the main class which loads the object:

package org.calvin.test;
 
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
 
import org.calvin.beans.SpringTest;
 
public class SpringDemo {
 
    public static void main(String a[]){
        String confFile = "applicationContext.xml";
        ApplicationContext context = new ClassPathXmlApplicationContext(confFile);
        SpringTest st = (SpringTest) context.getBean("springTest");
        st.getFileManager().getDirectory("xxx");
    }
}

Now you will be able to get to fileManager and get the directory via Spring DI. As you can see, A Spring bean is basically an object managed by Spring. More specifically, it is an object that is instantiated, configured and otherwise managed by a Spring Framework container. Spring is a POJO-driven although it doesn’t necessarily have to be. That means it is using traditional style to create objects. No strings attached to complicate things.

  1. Google Guice (pronounced as Juice)

Guice is a lightweight dependency injection framework for Java 6 and above. This framework which is released by Google is under the Apache License, meaning you can use it freely as long as you preserve the copyright notice and disclaimers. The main difference with Guice Framework compared to Spring Framework is that Guice uses Annotations. Annotations in Java are first introduced in Java 5, but it was integrated into the Javac compiler in version 1.6 which is probably why Guice is supported for Java 6 and above. There are ways to bind with Annotations in Spring as well. Honestly, I do not see much differences between Spring and Guice. I actually did not like Spring for XML-Based configuration. However, with the newer version of Spring, there are ways around Spring where you can avoid XML definition and be similar to how Guice does its injection.

Here are some useful annotations in Guice:

  • @Inject - It tells where the injection is happening, you can place on constructors, methods or even fields
  • @Qualifier - It defines the identity of objects. It has close relationship to @Named annotation
  • @Named - It is used with @Inject annotation. You can use @Qualifier to name object and use @Named to use it.
  • @Scope - It tells life span of injecting object. If not defined, will create a new object each time. If defined, thread-safe becomes important.
  • @Singleton - Similar to @Scope. Basic to DI Framework.

First, just like Spring, you need the dependencies satisfied provided by Google.

<dependency>
    <groupId>com.google.inject</groupId>
    <artifactId>guice</artifactId>
    <version>3.0</version>
</dependency>

Sample Code:

pacakage org.calvin.guice;

import com.google.inject.Inject;
import com.google.inject.AbstractModule;

public class Car {
    public void doSomeThing() {
        System.out.println("Print SomeThing");
    }
}

class EngineService {
    private Car car;

    @Inject
    public EngineService(Car car) {
        this.car = car;
    }

    public void doSomeThing() {
        System.out.println("Print SomeThing");
    }
}

class CarModule extends AbstractModule {
    @Override
    protected void configure() {
        bind(Car.class);
    }
}

What’s important above is that it binds Car.class via AbstractModule which is provided by Google. Let’s test it out.

package org.calvin.guice;

import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;

import org.junit.Before;
import org.junit.Test;

import com.google.inject.Guice;
import com.google.inject.Injector;

public class EngineServiceTest {

    private Injector injector = null;

    @Before
    public void setUp() {
        injector = Guice.createInjector(new CarModule());
        assertThat(injector, is(not(nullValue())));
    }

    @Test
    public void testGetEngineService() {
        EngineService engineService = injector.getInstance(EngineService.class);
        engineService.doSomeThing();
        engineService.getCar().doSomeThing();
        assertThat(engineService, is(not(nullValue())));
    }

    @Test
    public void testGetCar() {
        Car car = injector.getInstance(Car.class);
        car.doSomeThing();
        assertThat(car, is(not(nullValue())));
    }
}

The output:

testGetEngineService is Print nothing Print SomeThing

testGetCar is Print SomeThing

As you can see, you can be flexible as you wish to create your object. Full examples discussed here are illustrated here.

Share this post

Me

I am a passionate programmer working in Vancouver. I strongly believe in art of algorithms and together with it to write clean and efficient software to build awesome products. If you would like to connect with me, choose one from below options :) You can also send me an email at