Browse DevX
Sign up for e-mail newsletters from DevX


Spring: Creating Objects So You Don't Have To

As a dependency injection framework (not to mention one of the more popular open source Java projects today), Spring links objects together using XML definitions. Find out about Spring and the ways you can invert control in your object programming.




Building the Right Environment to Support AI, Machine Learning and Deep Learning

ne of the more exciting open-source Java frameworks that has gathered steam in the last year is Spring. Spring aims to minimize dependency of application components by providing a plug-in architecture. Because Spring links objects together instead of the objects linking themselves together, it is categorized as a 'dependency injection' or 'inversion of control' framework.

Spring's object linking is defined in XML files, thus you can plug-in different components during runtime, or for different application configurations. This is particularly useful for applications that do unit testing or applications that deploy different configurations for different customers.

There are three primary types of dependency injection: setter-based, constructor-based, and interface-based injection. Spring supports both setter-based and constructor-based injection. As you will see later, this means Spring is able to create an object by passing objects references to its constructor and can modify the state of the object by calling its setter methods.

The terms 'dependency injection' and 'inversion of control' are often used interchangeably. Martin Fowler recently elaborated on the terminology, stating that dependency injection is a specific type of inversion of control. Specifically, dependency injection is a pattern where the responsibility for object creation and object linking is removed from the objects themselves and moved into a factory. Thus, dependency injection inverts the control for object creation and linking.

Though dependency injection is the basis of the Spring framework, Spring also provides a rich set of tools built on top of its core dependency injection functionality. Spring provides an MVC framework, support for several presentation frameworks, a transaction management framework, DAO support, support for several O/R mapping tools, and more.

This article is the first in a two-part series. I will introduce you to Spring's basic dependency injection functionality and its JDBC toolkit. In the next article, I will introduce you to several other Spring features by building a simple Web-application using Spring's MVC framework.

Injecting Dependency Using Factories
In this section I'll show you an example of a class that you might want to refactor in order to use dependency injection. First, you'll refactor the class programmatically, so that you can see how the pattern works without the use of a dependency injection framework. After that, you'll explore how to inject dependencies using Spring.

The following example demonstrates a tight coupling between two classes (the DataProcessor class and the FileDataReader class).

class DataProcessor… public Result processData() { FileDataReader dataReader = new FileDataReader("/data/file1.data"); Data data = dataReader.readData(); return data.calculateResult(); } client code… DataProcessor fileDataProcessor = new DataProcessor(); Result result = fileDataProcessor.processData();

DataProcessor depends explicitly on FileDataReader. If we wanted to process data from another source (say a database) we would have to refactor the existing DataProcessor to operate on a more generic DataReader interface. One way to decouple the two is to push the creational responsibility for the DataReader out to the client code.

Here is the code, after refactoring:

class DataProcessor… private DataReader dataReader; public DataProcessor(DataReader reader) { this.dataReader = reader; } public Result processData() { Data data = dataReader.readData(); return data.calculateResult(); } interface DataReader… public Data readData(); client code… FileDataReader dataReader = new FileDataReader("/data/file1.data"); DataProcessor fileDataProcessor = new DataProcessor(dataReader); Result result = fileDataProcessor.processData();

Notice that the DataProcessor class no longer operates on FileDataReader, but rather on the DataReader interface that FileDataReader implements. By generalizing the interface, we've made DataProcessor more generic and reusable. The problem now is that any client code that wants to process data in a file has to create and link all the objects itself. Instead, we could inject the dependency between the DataProcessor and the DataReader using one or more factory classes.

One way would be as follows:

class DataProcessorFactory… public static DataProcessor getFileDataProcessor() { DataReader reader = new FileDataReader("/data/file1.data");; DataProcessor dataProcessor = new DataProcessor(reader); return dataProcessor; } client code… DataProcessor fileDataProcessor = DataProcessorFactory.getFileDataProcessor(); Result result = fileDataProcessor.processData();

The DataProcessorFactory class is now responsible for creating and assembling our objects, and thus we have inverted control by way of dependency injection.

Thanks for your registration, follow us on our social networks to keep up-to-date