Over a million developers have joined DZone.

Spring Dependency Injection - An Introductory Tutorial

Looking for useful subversion pre-commit hooks? Maybe this script is for you. It's a Linux bash shell script and also makes use of python.

· Java Zone

Learn more about Kotlin, a new programming language designed to solve problems that software developers face every day brought to you in partnership with JetBrains.

This article discusses dependency injection in a tutorial format. It covers some of the newer features of Spring DI such as annotations, improved XML configuration and more.

Dependency Injection

Dependency Injection (DI) refers to the process of supplying an external dependency to a software component. DI can help make your code architecturally pure. It aids in design by interface as well as test-driven development by providing a consistent way to inject dependencies. For example, a data access object (DAO) may depend on a database connection. Instead of looking up the database connection with JNDI, you could inject it.

One way to think about a DI container like Spring is to think of JNDI turned inside out. Instead of an object looking up other objects that it needs to get its job done (dependencies), a DI container injects those dependent objects. This is the so-called Hollywood Principle, “Don't call us” (lookup objects), “we’ll call you” (inject objects).

If you have worked with CRC cards you can think of a dependency as a collaborator, i.e., an object that another object needs to perform its role.
Let's say that you have an automated teller machine (ATM) and it needs the ability to talk to a bank. It uses what it calls a transport object to do this. In this example, a transport object handles the low-level communication to the bank.

This example could be represented by either of the  two interfaces as follows:

AutomatedTellerMachine interface

package com.arcmind.springquickstart;

import java.math.BigDecimal;

public interface AutomatedTellerMachine {
        void deposit(BigDecimal bd);
        void withdraw(BigDecimal bd);
}

 

ATMTransport interface

package com.arcmind.springquickstart;

public interface ATMTransport {
        void communicateWithBank(byte [] datapacket);
}

Now the AutomatedTellerMachine needs a transport to perform its intent, namely withdraw money and deposit money. To carry out these tasks, the AutomatedTellerMachine may depend on many objects and collaborates with its dependencies to complete the work.

An implementation of the AutomatedTellerMachine may look like this:

AutomatedTellerMachine implementation:

package com.arcmind.springquickstart;

import java.math.BigDecimal;

public class AutomatedTellerMachineImpl implements AutomatedTellerMachine{

        private ATMTransport transport;

        public void deposit(BigDecimal bd) {
          ...
                transport.communicateWithBank(...);
        }

        public void withdraw(BigDecimal bd) {
          ...
                transport.communicateWithBank(...);
        }

        public void setTransport(ATMTransport transport) {
                this.transport = transport;
        }

}

The AutomatedTellerMachineImpl does not know or care how the transport withdraws and deposits money from the bank. This level of indirection allows us to replace the transport with different implementations such as in the following example:

Three example transports: SoapAtmTransport, StandardAtmTransport and SimulationAtmTransport

package com.arcmind.springquickstart;

public class SoapAtmTransport implements ATMTransport {

        public void communicateWithBank(byte[] datapacket) {
           ...
        }

}
package com.arcmind.springquickstart;

public class StandardAtmTransport implements ATMTransport {

        public void communicateWithBank(byte[] datapacket) {
          ...
        }

}



package com.arcmind.springquickstart;

public class SimulationAtmTransport implements ATMTransport {

        public void communicateWithBank(byte[] datapacket) {
                ...
        }

}

 

Notice the possible implementations of the ATMTransport interface. The AutomatedTellerMachineImpl does not know or care which transport it uses. Also, for testing and developing, instead of talking to a real bank, notice that you can use the SimulationAtmTransport.



About the author

Rick Hightower is CTO of Mammatus and is an expert on Java and Cloud Computing. Rick is invovled in Java CDI advocacy and Java EE. CDI Implementations - Resin Candi - Seam Weld - Apache OpenWebBeans


The concept of DI transcends Spring. Thus, you can accomplish DI without Spring as follows:


DI without Spring

 

package com.arcmind.springquickstart;

import java.math.BigDecimal;

public class AtmMain {

        public void main (String[] args) {
                AutomatedTellerMachine atm = new AutomatedTellerMachineImpl();
                ATMTransport transport = new SoapAtmTransport();
                /* Inject the transport. */           
                ((AutomatedTellerMachineImpl)atm).setTransport(transport);

                atm.withdraw(new BigDecimal("10.00"));

                atm.deposit(new BigDecimal("100.00"));
        }

}

Then injecting a different transport is a mere matter of calling a different setter method as follows:

Injecting a different dependency

                ATMTransport transport = new SimulationAtmTransport();
                ((AutomatedTellerMachineImpl)atm).setTransport(transport);

To use Spring to inject a dependency you could do the following:

Using Spring to manage dependencies

package com.arcmind.springquickstart;

import java.math.BigDecimal;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AtmMain {

        public static void main (String[] args) {
                ApplicationContext appContext = new ClassPathXmlApplicationContext("classpath:./spring/applicationContext.xml");
                AutomatedTellerMachine atm = (AutomatedTellerMachine) appContext.getBean("atm");

                atm.withdraw(new BigDecimal("10.00"));

                atm.deposit(new BigDecimal("100.00"));
        }

} 

/spring/applicationContext.xml file

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="
                http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

        <bean id="atmTransport" class="com.arcmind.springquickstart.SoapAtmTransport" />


        <bean id="atm" class="com.arcmind.springquickstart.AutomatedTellerMachineImpl">
                <property name="transport" ref="atmTransport" />
        </bean>

</beans>

 

Figure 1 illustrates how Spring injects the dependency using property setter method injection. 

[img_assist|nid=5868|title=|desc=|link=none|align=undefined|width=720|height=540]


The application context is the central interface to the Spring DI container. In the application context, you declare two beans, atmTransport and atm, with a bean tag. Then you use the property tag to inject the atmTransport bean into the transport property. This effectively calls the setter method of the AutomatedTellerMachineImpl transport property (setTransport(...)).


The major capabilities that the application context provides include (taken from API docs):

  • Bean factory methods for accessing application components
  • The ability to load file resources in a generic fashion
  • The ability to resolve messages, supporting internationalization

The focus of this article is bean factory methods and DI.



About the author

Rick Hightower is CTO of Mammatus and is an expert on Java and Cloud Computing. Rick is invovled in Java CDI advocacy and Java EE. CDI Implementations - Resin Candi - Seam Weld - Apache OpenWebBeans

Using constructor instead of setter

Another option when using Spring is to use constructor arguments instead of setter methods to inject dependencies. This keeps things more pure from an object-oriented design standpoint as an object has to be created with all of its collaborators (a.k.a. dependencies) it needs to fulfill its role.

Using constructors, injection is much like using setter methods as follows:

Application context for constructor injection

 <bean id="standardTransport" class="com.arcmind.springquickstart.StandardAtmTransport"/>

        <bean id="atm" class="com.arcmind.springquickstart.AutomatedTellerMachineImpl">
                <constructor-arg ref="standardTransport" />
        </bean>

 

Notice the use of the constructor-arg tag. This implies that the constructor takes transport as a single argument.

Adding a constructor to AutomatedTellerMachineImpl

public class AutomatedTellerMachineImpl implements AutomatedTellerMachine{

        private ATMTransport transport;

        public AutomatedTellerMachineImpl (ATMTransport transport) {
                this.transport = transport;
        }

The above example should keep the object purists in your group happy. However, the setter injection style makes test-driven development a bit easier. In practice, the setter method approach is used more often.
Figure 2 illustrates how the constructor injection occurs. 

[img_assist|nid=5869|title=|desc=|link=none|align=undefined|width=720|height=540] 

If you have many constructors in the same class with a variable number of arguments, Spring will try to pick the best fit. However, you can give Spring some hints as follows:

Application context for constructor injection with a hint for Spring

        <bean id="atm" class="com.arcmind.springquickstart.AutomatedTellerMachineImpl">
                <constructor-arg index="0" ref="standardTransport" />
        </bean>

Under some circumstances, you can even specify the type attribute that you want Spring to use to resolve the constructor argument in cases when there are more than one possible constructor match.  Most times, you don't have to specify index or type. Your mileage may vary.



About the author

Rick Hightower is CTO of Mammatus and is an expert on Java and Cloud Computing. Rick is invovled in Java CDI advocacy and Java EE. CDI Implementations - Resin Candi - Seam Weld - Apache OpenWebBeans


Spring and Annotation driven DI

Seam, and Guice pioneered the use of DI using annotation instead of XML. Spring also added this support and in typical Spring fashion, it does this in a flexible non-invasive manner.

Let's start off with a simple example. Let's say that you misconfigured the AutomatedTellerMachineImpl and forgot to inject a dependency as follows:
Opps forgot to inject the transport

        <bean id="atmTransport" class="com.arcmind.springquickstart.SoapAtmTransport" />


        <bean id="atm" class="com.arcmind.springquickstart.AutomatedTellerMachineImpl">
        </bean>

You might get an error like this:

Typical error from misconfiguring a bean

Exception in thread "main" java.lang.NullPointerException
        at com.arcmind.springquickstart.AutomatedTellerMachineImpl.withdraw(AutomatedTellerMachineImpl.java:25)
        at com.arcmind.springquickstart.AtmMain.main(AtmMain.java:14)

In a deployed application, this error could be quite cryptic. If you used the @Required annotation, you could ask Spring to scan the beans and look for missing dependencies as follows:

AutomatedTellerMachineImpl using @Required on the setter method of the transport property

import org.springframework.beans.factory.annotation.Required;

public class AutomatedTellerMachineImpl implements AutomatedTellerMachine{

        private ATMTransport transport;

        @Required
        public void setTransport(ATMTransport transport) {
                this.transport = transport;
        }

 

Now, when you run this after forgetting to configure a transport, you would get this message:

Caused by: org.springframework.beans.factory.BeanInitializationException: Property 'transport' is required for bean 'atm'

This is clearer and makes it easier to develop and debug applications. To enable this dependency checking feature, you must use context:component-scan or the context:annotation-config tags. This is discussed in more detail later. Here is the last example using context:annotation-config:

Application context file using annotation-config tag

<?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"
        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">

        <context:annotation-config/>

        <bean id="atmTransport" class="com.arcmind.springquickstart.SoapAtmTransport" />


        <bean id="atm" class="com.arcmind.springquickstart.AutomatedTellerMachineImpl">
                <property name="transport" ref="atmTransport"/>
        </bean>

</beans>

Using @Autowire to define a default transport

You may want to define a default transport for an AutomatedTellerMachine. You could do this with the @Autowire and @Qualifier annotations as follows:

Using @Autowire and @Qualifier annotations to do DI

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;

public class AutomatedTellerMachineImpl implements AutomatedTellerMachine{

        @Autowired (required=true)
        @Qualifier ("standardTransport")
        private ATMTransport transport;

 When using Spring annotations for DI, you do not need to have setter methods (or special constructors) any longer. Spring can inject directly into private fields or you have the option of annotating the setter methods instead. The applicationContext for this example looks like this:

Many transports configured in applicationContext, no injection specified in 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"
        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">

        <context:annotation-config/>

        <bean id="soapTransport" class="com.arcmind.springquickstart.SoapAtmTransport" />
        <bean id="standardTransport" class="com.arcmind.springquickstart.StandardAtmTransport" />
        <bean id="simulationTransport" class="com.arcmind.springquickstart.SimulationAtmTransport" />


        <bean id="atm" class="com.arcmind.springquickstart.AutomatedTellerMachineImpl"/>


</beans>

Notice that no transport for injection is specified in this file. The annotations specify which transport gets injected by default. Figure 3 illustrates injection using this technique. 

[img_assist|nid=5870|title=|desc=|link=none|align=undefined|width=720|height=540] 

You could override which bean gets set by using standard Spring injection. In this way, you have a default (standardTransport) that can be overridden. Here is an example of overriding with another transport when you have a setter method for transport.

Overriding the annotation in the application context file

        <bean id="soapTransport" class="com.arcmind.springquickstart.SoapAtmTransport" />
        <bean id="standardTransport" class="com.arcmind.springquickstart.StandardAtmTransport" />
        <bean id="simulationTransport" class="com.arcmind.springquickstart.SimulationAtmTransport" />


        <bean id="atm" class="com.arcmind.springquickstart.AutomatedTellerMachineImpl">
                <property name="transport" ref="simulationTransport"/>
        </bean>

The XML DI injection takes precedence over the annotation. Therefore, the annotation is the "reasonable default", but the application context file has the final word.

 

Avoiding hard-wiring beans directly to other beans with @Qualifier and qualifier tag


For an extra level of indirection, you can add a qualifier to a bean in the configuration file and then specify which type of transport is needed in the AutomatedTellerMachineImpl as follows:

Using @Qualifier for an extra level of indirection

public class AutomatedTellerMachineImpl implements AutomatedTellerMachine{

        @Autowired (required=true)
        @Qualifier ("default")
        private ATMTransport transport;

Using qualifier tag in applicationContext.xml

        <bean id="soapTransport" class="com.arcmind.springquickstart.SoapAtmTransport" />
        <bean id="standardTransport" class="com.arcmind.springquickstart.StandardAtmTransport">
                <qualifier value="default"/> 
                <!-- NOTE ADDED THIS QUALIFIER that marks this as default -->
        </bean>
        <bean id="simulationTransport" class="com.arcmind.springquickstart.SimulationAtmTransport" />


        <bean id="atm" class="com.arcmind.springquickstart.AutomatedTellerMachineImpl"/>

With this extra level of indirection, you are not hard-wiring beans directly to other beans, and if you decide that you should use a new default transport object you don't have to rewire every dependent bean.
Figure 4 illustrates injection using this technique. 

[img_assist|nid=5871|title=|desc=|link=none|align=undefined|width=720|height=540]



About the author

Rick Hightower is CTO of Mammatus and is an expert on Java and Cloud Computing. Rick is invovled in Java CDI advocacy and Java EE. CDI Implementations - Resin Candi - Seam Weld - Apache OpenWebBeans


Avoiding XML hell with component-scan tag and @Service, @Component, @Repository annotations

Imagine an application with hundreds of managed objects and the size of the XML configuration file(s). You can manage objects with Spring without putting them in the applicationContext files by marking them with @Service, @Component, or @Repository, and telling Spring where to find the objects. Spring will next scan the classpath looking for these beans and then automatically manage their dependencies.
To perform this feat, you must configure a context:component-scan tag passing the packages you would like Spring to scan as follows:

Using component-scan tag in applicationContext.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"
        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">


        <context:component-scan base-package="com.arcmind.springquickstart"/>

</beans>

 

Then you mark your beans with the @Service, @Component, or @Repository as follows:

AutomatedTellerMachine class using @Service

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

@Service ("atm")
public class AutomatedTellerMachineImpl implements AutomatedTellerMachine{

        @Autowired (required=true)
        @Qualifier ("default")
        private ATMTransport transport;

 

Three transports using @Component

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

@Component("standardTransport")
@Qualifier("default")
public class StandardAtmTransport implements ATMTransport {

        public void communicateWithBank(byte[] datapacket) {
                ...
        }

}

@Component("soapTransport")
public class SoapAtmTransport implements ATMTransport {

        public void communicateWithBank(byte[] datapacket) {
                ...
        }

}

@Component("simulationTransport")
public class SimulationAtmTransport implements ATMTransport {

        public void communicateWithBank(byte[] datapacket) {
                ...
        }

}

 

Notice that there is a @Qualifier annotation used in the StandardAtmTransport to denote it as the default transport for this application. For new projects, it makes sense to use annotations for objects that don't often change their dependencies. Avoiding XML and using annotation is the new trend in DI; some say it is a best practice. Figure 5 illustrates injection using this technique.

[img_assist|nid=5872|title=|desc=|link=none|align=undefined|width=720|height=540]



About the author

Rick Hightower is CTO of Mammatus and is an expert on Java and Cloud Computing. Rick is invovled in Java CDI advocacy and Java EE. CDI Implementations - Resin Candi - Seam Weld - Apache OpenWebBeans


Configuring objects

In addition to injecting dependencies, Spring allows you to configure objects with primitive and basic types. Let's say that the SoapAtmTransport sometimes has to work in areas where the connection is not so great, so you decide to add a retries property to the SoapAtmTransport as follows:

SoapAtmTransport with retries

public class SoapAtmTransport implements ATMTransport {

        private int retries=3;

        public SoapAtmTransport() {
        }

        public SoapAtmTransport(int retries) {
                this.retries = retries;
        }

        public void setRetries(int retries) {
                this.retries = retries;
        }

        public void communicateWithBank(byte[] datapacket) {
                System.out.printf("SOAP Transport retries %d: %s \n", retries, new String(datapacket));
        }

}

Notice that you can pass the retries to the constructor or call the setter method with the number or retries as follows:

Injecting the number of retries with the setter method

        <bean id="soapTransport" class="com.arcmind.springquickstart.SoapAtmTransport">
                <property name="retries" value="5"/>
        </bean>


Injecting the number of retires with a constructor arg

        <bean id="soapTransport" class="com.arcmind.springquickstart.SoapAtmTransport">
                <constructor-arg value="6"/>
        </bean>

 


Figure 6 illustrates configuring retries using setter method injection. 

[img_assist|nid=5873|title=|desc=|link=none|align=undefined|width=720|height=540] 


Figure 7 illustrates configuring retries using constructor arguments. 

[img_assist|nid=5874|title=|desc=|link=none|align=undefined|width=720|height=540]

Since this type of configuration is so common, Spring has a shortcut to simplify property value injection as follows:

Using p namespace in an applicationContext.xml file

<?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:p="http://www.springframework.org/schema/p" 
        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">


        <bean id="soapTransport" class="com.arcmind.springquickstart.SoapAtmTransport" p:retries="7"/>

        <bean id="atm" class="com.arcmind.springquickstart.AutomatedTellerMachineImpl">
                <constructor-arg index="0" ref="soapTransport" />
        </bean>

</beans>

Notice the use of p:retries="7" is much less verbose than the previous example that used the property tag to set the value. If you are using the Spring IDE plugin for Eclipse, you will get code completion for the p:property-name-syntax. Figure 8 illustrates configuring retries using the shortcut notation added in Spring 2.x. 

[img_assist|nid=5875|title=|desc=|link=none|align=undefined|width=720|height=540] 


Spring allows you to configure all primitive types (int, byte, long, etc.), as well as wrapper objects (Integer, Byte, Long, etc.), and many basic types (String, URL, Class, File, etc.).



About the author

Rick Hightower is CTO of Mammatus and is an expert on Java and Cloud Computing. Rick is invovled in Java CDI advocacy and Java EE. CDI Implementations - Resin Candi - Seam Weld - Apache OpenWebBeans


Using property place holder configurer

Let's say for each installation of an ATM, the installer may need to configure the number of retries. You probably don't want the installer messing with your XML file for your application context because it is too much like code and too many things could go wrong. Instead, perhaps you could just edit a properties file. The properties file could have properties for each of the things that may vary for a given installation of an AutomatedTellerMachineImpl.

atm.properties Properties file

transport.retries=8

applicationContext.xml using property-placeholder tag

<?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:p="http://www.springframework.org/schema/p" 
        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">

        <context:property-placeholder location="classpath:atm.properties"   />


        <bean id="soapTransport" class="com.arcmind.springquickstart.SoapAtmTransport" p:retries="${transport.retries}"/>

        <bean id="atm" class="com.arcmind.springquickstart.AutomatedTellerMachineImpl">
                <constructor-arg index="0" ref="soapTransport" />
        </bean>

</beans>

Notice the property-placeholder loads the atm.properties file from the classpath. Then you use the transport.retries defined in the atm.properties file as follows: p:retries="${transport.retries}".
Figure 9 illustrates using the property placeholder configurer. 

[img_assist|nid=5876|title=|desc=|link=none|align=undefined|width=720|height=540] 


You could load properties file from the file system using file: instead of classpath: in the location as follows:

Loading the properties file from the file system with the property-placeholder

        <context:property-placeholder location="file:./src/main/resources/atm.properties"   />


        <bean id="soapTransport" class="com.arcmind.springquickstart.SoapAtmTransport" p:retries="${transport.retries}"/>

        <bean id="atm" class="com.arcmind.springquickstart.AutomatedTellerMachineImpl">
                <constructor-arg index="0" ref="soapTransport" />
        </bean>



About the author

Rick Hightower is CTO of Mammatus and is an expert on Java and Cloud Computing. Rick is invovled in Java CDI advocacy and Java EE. CDI Implementations - Resin Candi - Seam Weld - Apache OpenWebBeans

Scopes and lifecycle


Spring supports the concepts of scopes. If you are familiar with JSP and Servlets, you may recall that they have request, session and application scopes. Objects put into request scope stay around for the duration of one request. Objects put into session scope stay around the entire user session (unless destroyed manually) while objects put into application scope stay around as long as the web application is running.

Spring scope support is very similar that of JSP and Servlets. Spring supports the following scopes: prototype, singleton, request, session and more. Plus you can configure you own scope handlers. Outside of a web application, Spring mainly supports two scopes out of the box: prototype and singleton. A singleton-scoped object is the default. It means that the object will stay around as long as the application context does (typically, very similar to application scope in a web application). A prototype scope means that every time that you ask for an object, Spring will create a new one. For example:

Two atms configured with different scopes

        <bean id="atm" class="com.arcmind.springquickstart.AutomatedTellerMachineImpl" scope="singleton">
                <constructor-arg index="0" ref="soapTransport" />
        </bean>

        <bean id="atmP" class="com.arcmind.springquickstart.AutomatedTellerMachineImpl" scope="prototype">
                <constructor-arg index="0" ref="soapTransport" />
        </bean>

If you looked up the atm twice, you would get the same object because it is in singleton scope; however, every time you looked up atmP, you would get a different object because it is in prototype scope. This is demonstrated by the following example:


Example demonstrating prototype vs. singleton

                AutomatedTellerMachine atm1 = (AutomatedTellerMachine) appContext.getBean("atm");
                AutomatedTellerMachine atm2 = (AutomatedTellerMachine) appContext.getBean("atm");
                assert atm1 == atm2; //First assert

                AutomatedTellerMachine atmP1 = (AutomatedTellerMachine) appContext.getBean("atmP");
                AutomatedTellerMachine atmP2 = (AutomatedTellerMachine) appContext.getBean("atmP");
                assert atmP1 != atmP2; //Second assert

 

Life cycle methods

Often times, you need an object to initialize itself after you have set all of the dependencies. Spring allows you to specify specify an init method as follows:

Specifying an init method with Spring (applicationContext.xml)

        <bean id="atm" class="com.arcmind.springquickstart.AutomatedTellerMachineImpl" scope="singleton" init-method="init">
                <constructor-arg index="0" ref="soapTransport" />
        </bean>

        <bean id="atmP" class="com.arcmind.springquickstart.AutomatedTellerMachineImpl" scope="prototype" init-method="init">
                <constructor-arg index="0" ref="soapTransport" />
        </bean>

Notice the use of the init-method attribute in the bean tag. The name of the method does not have to be init.
Here is the init method defined in Java. (There are also a few more methods for the transport to add to the flavor of the of the example and a shutdown method which the article will discuss in a moment).


Init Method and Shutdown method in Java

public class AutomatedTellerMachineImpl implements AutomatedTellerMachine{


        public void init () {
                System.out.println("INIT");
                transport.connect();
        }

        public void shutdown () {
                System.out.println("SHUTDOWN");
                transport.close();
        }

 

The atm bean's init method gets called right after your first load the application context (you can change this by setting the lazy-init attribute to "true"). The prototype atmP bean's init method gets called every time you look it up in the application context.

You can also specify a clean up method using the attribute destroy-method as follows:

Using destroy-method attribute

        <bean id="atm" class="com.arcmind.springquickstart.AutomatedTellerMachineImpl" scope="singleton" 
                init-method="init" destroy-method="shutdown">
                <constructor-arg index="0" ref="soapTransport" />
        </bean>

        <bean id="atmP" class="com.arcmind.springquickstart.AutomatedTellerMachineImpl" scope="prototype" 
                init-method="init" destroy-method="shutdown">
                <constructor-arg index="0" ref="soapTransport" />
        </bean>

 

The destroy method would never get called by Spring on atmP because it does not manage the life cycle of prototype beans after creation. The destroy method on atm would only get called if someone gracefully closed the application context which Spring does for some application contexts (this is beyond the scope of this introductory tutorial). Figure 10 illustrates using lifecycle methods. 

[img_assist|nid=5877|title=|desc=|link=none|align=undefined|width=720|height=540]

Conclusion

DI can help make your code architecturally pure. It aids in using a design-by-interface approach as well as test-driven development by providing a consistent way to inject dependencies. You don't need Spring to use DI. You could use DI with plain old Java. However, Spring provides a very nice, powerful DI container.
There are other DI containers and frameworks out there such as Plexus, Pico container, JBoss microcontainer, and, more recently, Guice. And, other frameworks allow DI like JSF, Seam and more. But, Spring is the de facto industry standard way to do DI.

What we did not cover is also interesting. We did not cover autowiring using by type or by name or constructor autowiring as these are features that developers just don't use in a production environments. A future tutorial titled, "DI details", will cover this as well as many other topics related to Spring DI like bean definitions, using lists, maps and sets, FactoryBeans, ApplicationContextAware, and, yes, autowiring.
The next item in this tutorial series will be AOP. Followed by Spring DAO and JPA support.

 

Rick Hightower serves as Chief Technology Officer for ArcMind Inc., a consulting and training firm specializing in Spring, JPA/Hibernate, and JSF. Rick enjoys writing and programming.

The Java Zone is brought to you in partnership with JetBrains.  Discover how powerful static code analysis and ergonomic design make development not only productive but also an enjoyable experience.

Topics:
java,frameworks,spring,java ee,di

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}