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.
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.
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.