Spring as a Factory
Spring provides a core factory pattern, which eliminates the need to manually program factory objects (usually realized as singletons). It also, as the documentation explains, "allows you to decouple the configuration and specification of dependencies from your actual program logic."
Developers who work on large software systems know that as a system grows the number of factory classes can become quite large. This is unfortunate, because most of these factory classes are fairly simple singletons that create objects and tie them together. There is a lot of code duplication because singletons make use of static methods and variables, which can't be inherited. Thus, every singleton must reimplement the same basic structure.
The fundamental benefit of the Spring framework is its ability to act as a factory to create objects. Spring reads a schematic defined in an external configuration file, creates and wires the objects together using reflection, and then passes the objects back to you. Think of Spring as a factory that you don't have to write any code for.
Here is what the example would look like if I were using Spring instead:
InputStream is = new FileInputStream("src/examples/spring/beans.xml");
BeanFactory factory = new XmlBeanFactory(is);
DataProcessor dataProcessor = (DataProcessor) factory.getBean("fileDataProcessor");
Result result = dataProcessor.processData();
As you can see, I created a factory using Spring's XmlBeanFactory class, which reads an XML file that declaratively defines the classes that I want to create and link together. Like all bean factories in Spring, this class implements the BeanFactory interface.
Here is what the beans.xml file looks like:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
The root element for a Spring configuration file is <beans>
. This element contains one or more <bean>
elements. A <bean>
describes any Plain Old Java Object (POJO) in your application code.
The name attribute (id can also be used) provides a unique name for your bean. This is the name that your code will reference to retrieve beans from Spring. For example, in the above client code we accessed the DataProcessor bean by passing in fileDataProcessor. The class attribute tells Spring which class to instantiate. The singleton attribute tells Spring that this bean is a singleton, and thus Spring will always return the same instance of this bean. If singleton is set to false, Spring will generate a new bean for every request.
The <constructor-arg> sub-element represents an argument that should be passed into the constructor when Spring is generating the bean. If a constructor takes more than one argument, you may have to specify which argument in the XML file maps to which argument in the actual constructor using the "index" attribute.
If an argument to a constructor or setter is another object, we can use the <ref> element to point to another bean definition in our configuration file. In the example, the fileDataProcessor bean references the fileDataReader bean. To pass a value into a constructor, we use the <value> element. The <value> element can be used to represent any built-in Java types such as int, long, String, boolean, etc. Spring will do all the work of converting the value to the appropriate type behind the scenes.
If you need to inject a collection through a setter or constructor, Spring also has built-in support for defining Lists, Maps, Sets, and Properties collection types. Listing 1 is an example that is straight out of the Spring documentation.