Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases now! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon

Learning Dependency Injection (DI)

Save for later
  • 15 min read
  • 08 Mar 2018

article-image

In this article by Sherwin John CallejaTragura, author of the book Spring 5.0 Cookbook, we will learn about implementation of Spring container using XML and JavaConfig,and also managing of beans in an XML-based container.

In this article,you will learn how to:

  • Implementing the Spring container using XML
  • Implementing the Spring container using JavaConfig
  • Managing the beans in an XML-based container

(For more resources related to this topic, see here.)


Implementing the Spring container using XML

Let us begin with the creation of theSpring Web Project using the Maven plugin of our STS Eclipse 8.3. This web project will be implementing our first Spring 5.0 container using the XML-based technique. Thisis the most conventional butrobust way of creating the Spring container.

The container is where the objects are created, managed, wired together with their dependencies, and monitored from their initialization up to their destruction.This recipe will mainly highlight how to create an XML-based Spring container.

Getting ready

Create a Maven project ready for development using the STS Eclipse 8.3. Be sure to have installed the correct JRE. Let us name the project ch02-xml.

How to do it…

After creating the project, certain Maven errors will be encountered. Bug fix the Maven issues of our ch02-xml projectin order to use the XML-based Spring 5.0 container by performing the following steps: 

  1. Open pom.xml of the project and add the following properties which contain the Spring build version and Servlet container to utilize:
    <properties>
    		<spring.version>5.0.0.BUILD-SNAPSHOT</spring.version>
    		<servlet.api.version>3.1.0</servlet.api.version>
    </properties>
    


    Add the following Spring 5 dependencies inside pom.xml. These dependencies are essential in providing us with the interfaces and classes to build our Spring container:

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

  2. It is required to add the following repositories where Spring 5.0 dependencies in Step 2 will be downloaded:
    <repositories>
    		<repository>
    			<id>spring-snapshots</id>
    			<name>Spring Snapshots</name>
    			<url>https://repo.spring.io/libs-snapshot</url>
    			<snapshots>
    				<enabled>true</enabled>
    			</snapshots>
    		</repository>
    </repositories>


    Then add the Maven plugin for deployment but be sure to recognize web.xml as the deployment descriptor. This can be done by enabling<failOnMissingWebXml>or just deleting the<configuration>tag as follows:

    <plugin>
    			<artifactId>maven-war-plugin</artifactId>
    			<version>2.3</version>
    			</plugin>
    <plugin>
    

  3. Follow the Tomcat Maven plugin for deployment, as explained in Chapter 1.
  4. After the Maven configuration details, check if there is a WEB-INF folder inside src/main/webapp. If there is none, create one. This is mandatory for this project since we will be using a deployment descriptor (or web.xml).
  5. Inside theWEB-INF folder, create a deployment descriptor or drop a web.xml template inside src/main/webapp/WEB-INF directory.
  6. Then, create an XML-based Spring container named as ch02-beans.xmlinside thech02-xml/src/main/java/ directory. The configuration file must contain the following namespaces and tags:
    <?xml version="1.0" encoding="UTF-8"?>
    <beans 
    	
    	
    	xsi_schemaLocation="http://www.springframework.org/schema/beans
          http://www.springframework.org/schema/beans/spring-beans.xsd
    		http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-																		context.xsd">
    </beans>
    


    You can generate this file using theSTS Eclipse Wizard (Ctrl-N) and under the module SpringSpring Bean Configuration File option

  7. Save all the files. Clean and build the Maven project. Do not deploy yet because this is just a standalone project at the moment.


How it works…

This project just imported three major Spring 5.0 libraries, namely the Spring-Core, Spring-Beans, and Spring-Context,because the major classes and interfaces in creating the container are found in these libraries. This shows that Spring, unlike other frameworks, does not need the entire load of libraries just to setup the initial platform. Spring can be perceived as a huge enterprise framework nowadays but internally it is still lightweight.

The basic container that manages objects in Spring is provided by the org.springframework.beans.factory.BeanFactoryinterfaceand can only be found in theSpring-Beansmodule. Once additional features are needed such as message resource handling, AOP capabilities, application-specific contexts and listener implementation, the sub-interface of BeanFactory, namely the org.springframework.context.ApplicationContextinterface, is then used.This ApplicationContext, found in Spring-Contextmodules, is the one that provides an enterprise-specific container for all its applications becauseit encompasses alarger scope of Spring components than itsBeanFactoryinterface.

The container created,ch02-beans.xml, anApplicationContext, is an XML-based configuration that contains XSD schemas from the three main libraries imported. These schemashave tag libraries and bean properties, which areessential in managing the whole framework. But beware of runtime errors once libraries are removed from the dependencies because using these tags is equivalent to using the libraries per se.

The final Spring Maven project directory structure must look like this:learning-dependency-injection-di-img-0

Implementing the Spring container using JavaConfig

Another option of implementing the Spring 5.0 container is through the use of Spring JavaConfig. This is a technique that uses pure Java classes in configuring the framework's container. This technique eliminates the use of bulky and tedious XML metadata and also provides a type-safe and refactoring-free approach in configuring entities or collections of objects into the container. This recipe will showcase how to create the container usingJavaConfig in a web.xml-less approach.

Getting ready

Create another Maven project and name the projectch02-xml. This STSEclipse project will be using a Java class approach including its deployment descriptor.

How to do it…

      1. To get rid of the usual Maven bugs, immediately open the pom.xmlof ch02-jc and add<properties>, <dependencies>, and <repositories>equivalent to what was added inthe Implementing the Spring Container using XMLrecipe.
      2. Next, get rid of the web.xml. Since the time Servlet 3.0 specification was implemented, servlet containers can now support projects without using web.xml. This is done by implementingthe handler abstract class called org.springframework.web.WebApplicationInitializer to programmatically configure ServletContext. Create aSpringWebinitializerclass and override its onStartup() method without any implementation yet:
        public class SpringWebinitializer implements
        	WebApplicationInitializer {
        	
        	  @Override
        	  public void onStartup(ServletContext container) throws
        			ServletException {
        	    }
        }
        

      3. The lines in Step 2 will generate some runtime errors until you add the following Maven dependency:
        <dependency>
        		<groupId>org.springframework</groupId>
        		<artifactId>spring-web</artifactId>
        		<version>${spring.version}</version>
        </dependency>

      4. In pom.xml, disable the<failOnMissingWebXml>.
      5. After the Maven details, create a class named BeanConfig, the ApplicationContext definition, bearing an annotation @Configuration at the top of it. The class must be inside the org.packt.starter.ioc.contextpackage and must be an empty class at the moment:
        @Configuration
        public class BeanConfig {   }

      6. Save all the files and clean and build the Maven project.How it works…

        The Maven project ch02-xml makes use of both JavaConfig and ServletContainerInitializer, meaning there will be no XML configuration from servlet to Spring 5.0 containers. The BeanConfigclass is the ApplicationContext of the project which has an annotation @Configuration,indicating that the class is used by JavaConfig as asource of bean definitions.This is handy when creating an XML-based configuration with lots of metadata.

        On the other hand,ch02-xmlimplemented org.springframework.web.WebApplicationInitializer,which is a handler of org.springframework.web.SpringServletContainerInitializer, the framework's implementation class to theservlet'sServletContainerInitializer. The SpringServletContainerInitializerisnotified byWebApplicationInitializerduring the execution of its startup(ServletContext) with regard to theprogramaticalregistration of filters, servlets, and listeners provided by the ServletContext . Eventually, the servlet container will acknowledge the status reported by SpringServletContainerInitialize,thus eliminating the use of web.xml.

        On Maven's side, the plugin for deployment must be notified that the project will not use web.xml.This is done through setting the<failOnMissingWebXml>to false inside its<configuration>tag.

        The final Spring Web Project directory structure must look like the following structure:learning-dependency-injection-di-img-1

        Managing the beans in an XML-based container


        Frameworks become popular because of the principle behind the architecture they are made up from. Each framework is built from different design patterns that manage the creation and behavior of the objects they manage. This recipe will detail how Spring 5.0 manages objects of the applications and how it shares a set of methods and functions across the platform.

        Getting ready

        The two Maven projects previously created will be utilized in illustrating how Spring 5.0 loads objects into the heap memory.We will also be utilizing the ApplicationContextrather than the BeanFactorycontainer in preparation for the next recipes involving more Spring components.

        How to do it…

        With our ch02-xml, let us demonstrate how Spring loads objects using the XML-based Application Context container:

        Unlock access to the largest independent learning library in Tech for FREE!
        Get unlimited access to 7500+ expert-authored eBooks and video courses covering every tech area you can think of.
        Renews at €18.99/month. Cancel anytime
      7. Create a package layer,org.packt.starter.ioc.model,for our model classes. Our model classes will be typical Plain Old Java Objects(POJO),by which Spring 5.0 architecture is known for.
      8. Inside the newly created package, create the classes Employeeand Department,whichcontain the following blueprints:
        public class Employee {
        	
        	private String firstName;
        	private String lastName;
        	private Date birthdate;
        	private Integer age;
        	private Double salary;
        	private String position;
        	private Department dept;
        	
        	public Employee(){
        		System.out.println(" an employee is created.");
        	}
        
        	public Employee(String firstName, String lastName, Date
                  birthdate, Integer age, Double salary, String position,
        			Department dept) {
        	his.firstName = firstName;
        	his.lastName = lastName;
        	his.birthdate = birthdate;
        	his.age = age;
        	his.salary = salary;
        	his.position = position;
        	his.dept = dept;
        		System.out.println(" an employee is created.");
              }
              // getters and setters
        }
        public class Department {
        	
        	private Integer deptNo;
        	private String deptName;
        	
        	public Department() {
        		System.out.println("a department is created.");
        	}
        	// getters and setters
        }
        

      9. Afterwards, open the ApplicationContextch02-beans.xml. Register using the<bean>tag our first set of Employee and Department objects as follows:
        <bean id="empRec1" class="org.packt.starter.ioc.model.Employee" />
        <bean id="dept1" class="org.packt.starter.ioc.model.Department" />
        

      10. The beans in Step 3 containprivate instance variables that havezeroes and null default values. Toupdate them, our classes havemutators or setter methodsthat can be used to avoid NullPointerException, which happens always when we immediately use empty objects. In Spring,calling these setters is tantamount to injecting data into the<bean>,similar to how these following objectsare created:
        <bean id="empRec2"
              class="org.packt.starter.ioc.model.Employee">
        	<property name="firstName"><value>Juan</value></property>
        	<property name="lastName"><value>Luna</value></property>
        	<property name="age"><value>70</value></property>
        	<property name="birthdate"><value>October 28,
                                                  1945</value></property>
        	<property name="position">
        <value>historian</value></property>
        	<property name="salary"><value>150000</value></property>
        	<property name="dept"><ref bean="dept2"/></property>
        </bean>
        	<bean id="dept2" class="org.packt.starter.ioc.model.Department">
        	<property name="deptNo"><value>13456</value></property>
        	<property name="deptName">
        <value>History Department</value></property>
        </bean>
        

      11. A<property>tag is equivalent to a setter definition accepting an actual value oran object reference. The nameattributedefines the name of the setter minus the prefix set with the conversion to itscamel-case notation. The value attribute or the<value>tag both pertain to supported Spring-type values (for example,int, double, float, Boolean, Spring). The ref attribute or<ref>provides reference to another loaded<bean>in the container. Another way of writing the bean object empRec2 is through the use of ref and value attributes such as the following:
        <bean id="empRec3"
                class="org.packt.starter.ioc.model.Employee">
        	<property name="firstName" value="Jose"/>
        	<property name="lastName" value="Rizal"/>
        	<property name="age" value="101"/>
        	<property name="birthdate" value="June 19, 1950"/>
        	<property name="position" value="scriber"/>
        	<property name="salary" value="90000"/>
        	<property name="dept" ref="dept3"/>
        </bean>
        <bean id="dept3" class="org.packt.starter.ioc.model.Department">
        	<property name="deptNo" value="56748"/>
        	<property name="deptName" value="Communication Department" />
        </bean>
        


        Another way of updating the private instance variables of the model objects is to make use of the constructors. Actual Spring data and object references can be inserted to the through the metadata:

        <bean id="empRec5" class="org.packt.starter.ioc.model.Employee">
        	<constructor-arg><value>Poly</value></constructor-arg>
        	<constructor-arg><value>Mabini</value></constructor-arg>
        <constructor-arg><value>
                       August 10, 1948</value></constructor-arg>
        	<constructor-arg><value>67</value></constructor-arg>
        	<constructor-arg><value>45000</value></constructor-arg>
        	<constructor-arg><value>Linguist</value></constructor-arg>
        	<constructor-arg><ref bean="dept3"></ref></constructor-arg>
        </bean>
        

      12. After all the modifications, save ch02-beans.xml.Create a TestBeans class inside thesrc/test/java directory. This class will load the XML configuration resource to the ApplicationContext container throughorg.springframework.context.support.ClassPathXmlApplicationContextand fetch all the objects created through its getBean() method.
        public class TestBeans { 
        	public static void main(String args[]){
        		
        		ApplicationContext context = new
        ClassPathXmlApplicationContext("ch02-beans.xml");
        System.out.println("application context loaded.");
        
        System.out.println("****The empRec1 bean****");
               Employee empRec1 = (Employee) context.getBean("empRec1");
        
        System.out.println("****The empRec2*****");
               Employee empRec2 = (Employee) context.getBean("empRec2");
               Department dept2 = empRec2.getDept();
        System.out.println("First Name: " +
        								empRec2.getFirstName());
        System.out.println("Last Name: " + empRec2.getLastName());
        System.out.println("Birthdate: " +
        								empRec2.getBirthdate());
        System.out.println("Salary: " + empRec2.getSalary());
        System.out.println("Dept. Name: " + dept2.getDeptName());
        
        System.out.println("****The empRec5 bean****");
               Employee empRec5 = context.getBean("empRec5",
        								Employee.class);
               Department dept3 = empRec5.getDept();
        System.out.println("First Name: " +
        								empRec5.getFirstName());
        System.out.println("Last Name: " + empRec5.getLastName());
        System.out.println("Dept. Name: " + dept3.getDeptName());
        	} 
        }
        


The expected output after running the main() thread will be:

an employee is created.
an employee is created.
a department is created.
an employee is created.
a department is created.
an employee is created.
a department is created.
application context loaded.
*********The empRec1 bean ***************
*********The empRec2 bean ***************
First Name: Juan
Last Name: Luna
Birthdate: Sun Oct 28 00:00:00 CST 1945
Salary: 150000.0
Dept. Name: History Department
*********The empRec5 bean ***************
First Name: Poly
Last Name: Mabini
Dept. Name: Communication Department


How it works…

The principle behind creating<bean>objects into the container is called the Inverse of Control design pattern. In order to use the objects, its dependencies, and also its behavior, these must be placed within the framework per se. After registering them in the container, Spring will just take care of their instantiation and their availability to other objects. Developer can just "fetch" them if they want to include them in their software modules,as shown in the following diagram:learning-dependency-injection-di-img-2

The IoC design pattern can be synonymous to the Hollywood Principle (“Don't call us, we’ll call you!”), which is a popular line in most object-oriented programming languages. The framework does not care whether the developer needs the objects or not because the lifespan of the objects lies on the framework's rules.

In the case of setting new values or updating values of the object's private variables, IoC has an implementation which can be used for "injecting" new actual values or object references to and it is popularly known as the Dependency Injection(DI) design pattern. This principle exposes all the to the public through its setter methods or the constructors. Injecting Spring values and object references to the method signature using the <property>tag without knowing its implementation is called the Method Injection type of DI. On the other hand, if we create the bean with initialized values injected to its constructor through<constructor-arg>, it is known as Constructor Injection.

To create the ApplicationContext container, we need to instantiate ClassPathXmlApplicationContext or FileSystemApplicationContext, depending on the location of the XML definition file. Since the file is found in ch02-xml/src/main/java/, ClassPathXmlApplicationContext implementation is the best option. This proves that the ApplicationContext is an object too,bearing all those XML metadata. It has several overloaded getBean() methods used to fetch all the objects loaded with it.

Summary

In this article we went overhow to create an XML-based Spring container, how to create the container using JavaConfig in a web.xml-less approach andhow Spring 5.0 manages objects of the applications and how it shares a set of methods and functions across the platform.

Resources for Article:


 




Further resources on this subject:
      • [article]
      • [article]
      • [article]