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:
(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:
<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>
<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>
<?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 SpringSpring Bean Configuration File option
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:
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…
public class SpringWebinitializer implements
WebApplicationInitializer {
@Override
public void onStartup(ServletContext container) throws
ServletException {
}
}
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
@Configuration
public class BeanConfig { }
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:
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
}
<bean id="empRec1" class="org.packt.starter.ioc.model.Employee" />
<bean id="dept1" class="org.packt.starter.ioc.model.Department" />
<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>
<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>
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:
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.