This chapter is taken from the book - Getting started with Spring Framework, 4th Edition (https://www.amazon.com/dp/1979962782/). You can download the code for the book from here: https://github.com/getting-started-with-spring/4thEdition
Chapter 1 – Introduction to Spring Framework
1-1 Introduction
In the traditional Java enterprise application development efforts, it was a developer’s responsibility to create well-structured, maintainable and easily testable applications. The developers used myriad design patterns to address these non-business requirements of an application. This not only led to low developer productivity, but also adversely affected the quality of developed applications.
Spring Framework (or ‘Spring’ in short) is an open source application framework that simplifies developing Java enterprise applications. It provides the infrastructure for developing well-structured, maintainable and easily testable applications. When using Spring Framework, a developer only needs to focus on writing the business logic of the application, resulting in improved developer productivity. You can use Spring Framework to develop standalone Java applications, web applications, applets, or any other type of Java application. You can visit the home page of Spring Framework project (https://projects.spring.io/spring-framework/) to view the reference documentation and APIs.
This chapter starts off with an introduction to Spring Framework modules and its benefits. At the heart of Spring Framework is its Inversion of Control (IoC) container, which provides dependency injection (DI) feature. This chapter introduces Spring’s DI feature and IoC container, and shows how to develop a standalone Java application using Spring. Towards the end of this chapter, we’ll look at the new features and enhancements that form part of Spring Framework 5 release. We’ll wrap this chapter up by looking at some of the projects that use Spring Framework as their foundation. This chapter will set the stage for the remaining chapters that delve deeper into the Spring Framework.
In this book, we’ll use an example Internet Banking application, MyBank, to introduce Spring Framework features.
1-2 Spring Framework modules
Spring Framework consists of multiple modules that are grouped based on the application development features they address. The following table describes the different module groups in Spring Framework and specifies the purpose served by some of the important modules in these groups:
1-3 Spring IoC container
1-4 Benefits of using Spring Framework
Consistent
approach to managing local and global
transactions
Chapter 1 – Introduction to Spring Framework
1-1 Introduction
In the traditional Java enterprise application development efforts, it was a developer’s responsibility to create well-structured, maintainable and easily testable applications. The developers used myriad design patterns to address these non-business requirements of an application. This not only led to low developer productivity, but also adversely affected the quality of developed applications.
Spring Framework (or ‘Spring’ in short) is an open source application framework that simplifies developing Java enterprise applications. It provides the infrastructure for developing well-structured, maintainable and easily testable applications. When using Spring Framework, a developer only needs to focus on writing the business logic of the application, resulting in improved developer productivity. You can use Spring Framework to develop standalone Java applications, web applications, applets, or any other type of Java application. You can visit the home page of Spring Framework project (https://projects.spring.io/spring-framework/) to view the reference documentation and APIs.
This chapter starts off with an introduction to Spring Framework modules and its benefits. At the heart of Spring Framework is its Inversion of Control (IoC) container, which provides dependency injection (DI) feature. This chapter introduces Spring’s DI feature and IoC container, and shows how to develop a standalone Java application using Spring. Towards the end of this chapter, we’ll look at the new features and enhancements that form part of Spring Framework 5 release. We’ll wrap this chapter up by looking at some of the projects that use Spring Framework as their foundation. This chapter will set the stage for the remaining chapters that delve deeper into the Spring Framework.
In this book, we’ll use an example Internet Banking application, MyBank, to introduce Spring Framework features.
1-2 Spring Framework modules
Spring Framework consists of multiple modules that are grouped based on the application development features they address. The following table describes the different module groups in Spring Framework and specifies the purpose served by some of the important modules in these groups:
Spring Framework 5 no longer supports developing portlet applications. If you want to develop portlet applications using Spring, stick to Spring Framework 4.3.x.
The above
table shows that Spring covers every aspect of enterprise application
development; you can use Spring for developing web applications, accessing
databases, managing transactions, creating unit and integration tests, and so
on. The Spring Framework modules are designed in such a way that you only need to include the modules that
your application needs. For instance, to use Spring’s DI feature in your
application, you only need to include the modules grouped under Core container. As you progress through
this book, you’ll find more details about various Spring modules and examples
that show how they are used in developing applications.
The naming convention
followed by the JAR files in a Spring Framework distribution is:
spring-<short-module-name>-<spring-version>.jar.
here, <short-module-name> is the short name of the Spring module,
like aop, beans, context, expressions,
and so on. And, the <spring-version>
is the Spring Framework version.
Following this naming convention,
the names of JAR files in Spring 5.0.1.RELEASE are: spring-aop-5.0.1.RELEASE.jar,
spring-beans-5.0.1.RELEASE.jar,
and so on.
Figure 1-1 shows the
inter-dependencies of Spring modules. You can infer from the figure that the
modules contained in the Core container
group are central to the Spring Framework, and other modules depend on it.
Equally important are the modules contained in the AOP and instrumentation group because they provide AOP features to
other modules in the Spring Framework.
Figure
1-1 Spring modules
inter-dependencies
Now that you have some basic idea about the
areas of application development covered by Spring, let’s look at the Spring
IoC container.
1-3 Spring IoC container
A Java application consists
of objects that interact with each other to provide application behavior. The
objects with which an object interacts are referred to as its dependencies. For instance, if an object
X interacts with objects Y and Z, then Y and Z are dependencies of object X. DI
(short for 'Dependency Injection') is a design pattern in which the
dependencies of an object are typically specified as arguments to its
constructor and setter methods. And, these dependencies are injected into the
object when it’s created.
In a Spring application,
Spring IoC container (also referred to as 'Spring container') is responsible
for creating application objects and injecting their dependencies. The
application objects that the Spring container creates and manages are referred
as beans. As the Spring container is
responsible for putting together application objects, you don’t need to
implement design patterns, like Factory, Service Locator, and so on, to compose
your application. DI is also referred to as Inversion of Control (IoC) because
the responsibility of creating and injecting dependencies is not with the application object, but
with the Spring container.
Let’s say that the MyBank
application (which is the name of our sample application) contains two objects,
FixedDepositController
and FixedDepositService. The following example listing shows
that the FixedDepositController object depends on FixedDepositService
object:
Example listing 1-1:
FixedDepositController
class
public
class FixedDepositController {
private FixedDepositService
fixedDepositService;
public FixedDepositController() {
fixedDepositService = new
FixedDepositService();
}
public boolean submit() {
//-- save the fixed deposit details
fixedDepositService.save(.....);
}
}
In the above example
listing, FixedDepositController’s constructor creates an instance
of FixedDepositService which is later used in FixedDepositController’s
submit
method. As FixedDepositController interacts with FixedDepositService,
FixedDepositService
represents a dependency of FixedDepositController.
To configure FixedDepositController
as a Spring bean, you first need to modify the FixedDepositController
class of example listing 1-1 such that it accepts FixedDepositService
dependency as a constructor argument or as a setter-method argument. The
following example listing shows the modified FixedDepositController
class:
Example listing 1-2:
FixedDepositController
class – FixedDepositService is passed as a constructor argument
public
class FixedDepositController {
private FixedDepositService
fixedDepositService;
public
FixedDepositController(FixedDepositService
fixedDepositService) {
this.fixedDepositService =
fixedDepositService;
}
public boolean submit() {
//-- save the fixed deposit details
fixedDepositService.save(.....);
}
}
The above example listing
shows that the FixedDepositService instance is now passed as a
constructor argument to the FixedDepositController instance. Now,
the FixedDepositController class can be configured as a
Spring bean. Notice that the FixedDepositController class
doesn’t implement or extend from any Spring interface or class.
In Spring-based
applications, information about application objects and their dependencies is
specified using configuration metadata.
Spring IoC container reads application’s configuration metadata to instantiate
application objects and inject their dependencies. The following example
listing shows the configuration metadata (in XML format) for MyBank application
that consists of FixedDepositController and FixedDepositService
classes:
Example listing 1-3:
MyBank application’s configuration metadata
<beans
.....>
<bean id="fdController"
class="sample.spring.controller.FixedDepositController">
<constructor-arg ref="fdService"
/>
</bean>
<bean id="fdService"
class="sample.spring.service.FixedDepositService"/>
</beans>
In the above example
listing, each <bean> element defines an application object that
is managed by the Spring container, and the <constructor-arg>
element specifies that an instance of FixedDepositService
is passed as an argument to FixedDepositController’s constructor.
The <bean> element is discussed in detail later in this
chapter, and the <constructor-arg> element is
discussed in chapter 2.
Spring
container reads the configuration metadata (like the one shown in example
listing 1-3) of an application and creates the application objects defined by <bean>
elements and injects their dependencies. Spring container makes use of Java Reflection API (http://docs.oracle.com/javase/tutorial/reflect/index.html) to create application objects and
inject their dependencies. The following figure summarizes how the Spring container
works:
Figure 1-2 Spring
container reads application’s configuration metadata and creates a
fully-configured application
The
configuration metadata can be supplied to the Spring container via XML (as
shown in example listing 1-3), Java annotations (refer chapter 6) and
programmatically through the Java code (refer chapter 7).
As the
Spring container is responsible for creating and managing application objects,
enterprise services (like transaction management, security, remote access, and
so on) can be transparently applied to the objects by the Spring container. The
ability of the Spring container to enhance the application objects with
additional functionality makes it possible for you to model your application
objects as simple Java objects (also referred to as POJOs or Plain Old Java Objects). Java classes corresponding to POJOs are referred
to as POJO classes,
which are nothing but Java classes that don’t implement or extend
framework-specific interfaces or classes. The enterprise services, like transaction
management, security, remote access, and so on, required by these POJOs are
transparently provided by the Spring container.
Now that
we know how Spring container works, let’s look at some examples that
demonstrate benefits of developing applications using Spring.
1-4 Benefits of using Spring Framework
In the
previous section, we discussed the following benefits of using Spring:
> Spring simplifies composing Java applications by
taking care of creating application objects and injecting their dependencies
> Spring promotes developing applications as POJOs
Spring
also simplifies interaction with JMS providers, JNDI, MBean servers, email
servers, databases, and so on, by providing a layer of abstraction that takes
care of the boilerplate code.
Let’s take
a quick look at a few examples to better understand the benefits of developing
applications using Spring.
Consistent
approach to managing local and global
transactions
If you are using Spring for
developing transactional applications,
you can use Spring’s declarative
transaction management support to manage transactions.
The following example
listing shows the FixedDepositService class of MyBank application:
Example
listing 1-4 – FixedDepositService
class
public
class FixedDepositService {
public FixedDepositDetails getFixedDepositDetails(
..... ) { ..... }
public boolean createFixedDeposit(FixedDepositDetails
fixedDepositDetails) { ..... }
}
FixedDepositService
class is a POJO class that defines methods to create and retrieve details of fixed
deposits. The following figure shows the form for creating a new fixed deposit:
Figure 1-3 HTML form for creating a new fixed deposit
A customer
enters the fixed deposit amount, tenure and email id information in the above
form and clicks the SAVE button to create a new fixed deposit.
The FixedDepositService’s createFixedDeposit
method (refer example listing 1-4) is invoked to create the fixed deposit. The createFixedDeposit
method debits the amount entered by the customer from his bank account and
creates a fixed deposit of the same amount.
Let’s say that information
about the bank balance of customers is stored in BANK_ACCOUNT_DETAILS
database table, and the fixed deposit details are stored in FIXED_DEPOSIT_DETAILS
database table. If a customer creates a fixed deposit of amount x,
amount x is subtracted from the BANK_ACCOUNT_DETAILS
table, and a new record is inserted in FIXED_DEPOSIT_DETAILS
table to reflect the newly created fixed deposit. If BANK_ACCOUNT_DETAILS
table is not updated or a new record
is not inserted in FIXED_DEPOSIT_DETAILS
table, it’ll leave the system in an inconsistent state. This means the createFixedDeposit
method must be executed within a transaction.
The database used by the MyBank
application represents a transactional
resource. In the traditional approach to perform a set of database
modifications as a single unit of work, you’ll first disable auto-commit mode
of JDBC connection, then execute SQL statements, and finally commit (or
rollback) the transaction. The following example listing shows the createFixedDeposit
method that uses the traditional approach to managing database transactions:
Example listing 1-5 –
Programmatically managing database transactions
using JDBC Connection object
import
java.sql.Connection;
import
java.sql.SQLException;
public
class FixedDepositService {
public FixedDepositDetails
getFixedDepositDetails( ..... ) { ..... }
public boolean createFixedDeposit(FixedDepositDetails
fixedDepositDetails) {
Connection con = ..... ;
try {
con.setAutoCommit(false);
//-- execute SQL statements that
modify database tables
con.commit();
} catch(SQLException sqle) {
if(con != null) {
con.rollback();
}
}
.....
}
}
The above example listing
shows that the createFixedDeposit method programmatically manages database
transactions using JDBC Connection object. Transactions that
are resource-specific, like the transactions associated with a JDBC Connection
object, are referred to as local
transactions.
The approach of using JDBC Connection
object to manage transactions is suitable for application scenarios in which a
single database (that is, a single transactional resource) is involved. When multiple
transactional resources are involved, JTA (Java Transaction API) is used for
managing transactions. For instance, if you want to send a JMS message to a
messaging middleware (a transactional resource) and update a database (another
transactional resource) in the same transaction, you must use a JTA transaction
manager to manage transactions. JTA transactions are also referred to as global (or distributed) transactions.
To use JTA, you fetch UserTransaction object (which is part
of JTA API) from JNDI and programmatically start and commit (or rollback)
transactions.
As you can
see, you can either use JDBC Connection (for local transactions) or UserTransaction (for
global transactions) object to programmatically manage transactions. It is
important to note that a local transaction cannot run within a global transaction. This means that if
you want database updates in createFixedDeposit method
(refer example listing 1-5) to be part of a JTA transaction, you need to modify
the createFixedDeposit method to use
the UserTransaction object for transaction management.
Spring simplifies
transaction management by providing a layer of abstraction that gives a consistent approach to managing both
local and global transactions. This means that if you write the createFixedDeposit
method (refer example listing 1-5) using Spring’s transaction abstraction, you
don’t need to modify the method when you switch from local to global
transaction management, or vice versa. Spring’s transaction abstraction is
explained in chapter 8.
Declarative transaction management
Security
JMX (Java
Management Extensions)
JMS (Java Message Service)
Caching
1-5
A simple Spring application
Creating
the configuration metadata
Example listing 1-14 – FixedDepositController class
Figure 1-7 summarizes how the Spring container
creates beans and injects their dependencies based on the configuration
metadata supplied by the applicationContext.xml file
(refer example listing 1-13) of MyBank application. The figure shows the
sequence of steps followed by the Spring IoC container to create FixedDepositController, FixedDepositService
and FixedDepositDao beans
and inject their dependencies. Before attempting to create beans, the Spring
container reads and validates the configuration metadata supplied by the applicationContext.xml
file. The order in which the beans are created by the Spring container depends
on the order in which they are defined in the applicationContext.xml
file. Spring container ensures that the dependencies of a bean are completely
configured before the setter method is invoked. For example, the FixedDepositController
bean is dependent on FixedDepositService
bean; therefore, Spring container configures the FixedDepositService
bean before invoking the setFixedDepositService
method of FixedDepositController
bean.
Creating
an instance of Spring container
Access
beans from the Spring container
At first, the ApplicationContext’s getBean method is invoked to retrieve an instance of FixedDepositController bean from the Spring container, followed by invocation of submit and get methods of FixedDepositController bean. The argument passed to the getBean method is the name of the bean whose instance you want to retrieve from the Spring container. The name of the bean passed to the getBean method must be the value of the id or name attribute of the bean that you want to retrieve. If no bean with the specified name is registered with the Spring container, an exception is thrown by the getBean method.
In example listing 1-16, to configure the FixedDepositController instance, we didn’t programmatically create an instance of FixedDepositService and set it on the FixedDepositController instance. Also, we didn’t create an instance of FixedDepositDao and set it on the FixedDepositService instance. This is because the task of creating dependencies, and injecting them into the dependent objects is handled by the Spring container.
The above output shows that the Spring container creates an instance of each of the beans defined in the applicationContext.xml file of MyBank application. Also, Spring container uses setter-based DI to inject an instance of FixedDepositService into FixedDepositController instance, and an instance of FixedDepositDao into the FixedDepositService instance.
Declarative transaction management
Spring gives you the option
to use declarative transaction management.
You can annotate a method with Spring’s @Transactional
annotation and let Spring handle transactions, as shown here:
Example
listing 1-6 – @Transactional
annotation usage
import
org.springframework.transaction.annotation.Transactional;
public
class FixedDepositService {
public FixedDepositDetails
getFixedDepositDetails( ..... ) { ..... }
@Transactional
public boolean
createFixedDeposit(FixedDepositDetails
fixedDepositDetails) { ..... }
}
The above example listing
shows that the FixedDepositService class doesn’t implement or extend
from any Spring-specific interface or class to use Spring’s transaction
management facility. The Spring Framework transparently provides transaction
management feature to @Transactional annotated createFixedDeposit
method. This shows that Spring is a non-invasive framework
because it doesn’t require your application objects to be dependent upon
Spring-specific classes or interfaces. As transaction management is taken care
by Spring, you don’t need to directly work with transaction management APIs to
manage transactions.
Security
Security is an important
aspect of any Java application. Spring Security (http://projects.spring.io/spring-security/)
is a project that is built on top of Spring Framework. Spring Security provides
authentication and authorization features that you can use for securing Java
applications.
Let’s say that the
following 3 user roles have been identified for the MyBank application: LOAN_CUSTOMER,
SAVINGS_ACCOUNT_CUSTOMER
and APPLICATION_ADMIN. A customer must be associated with the SAVINGS_ACCOUNT_CUSTOMER
or the APPLICATION_ADMIN role to invoke the createFixedDeposit
method of FixedDepositService class (refer example listing 1-6). Using
Spring Security you can easily address this requirement by annotating createFixedDeposit
method with Spring Security’s @Secured annotation, as shown
in the following example listing:
Example
listing 1-7 – Secured createFixedDeposit
method
import
org.springframework.transaction.annotation.Transactional;
import
org.springframework.security.access.annotation.Secured;
public
class FixedDepositService {
public FixedDepositDetails
getFixedDepositDetails( ..... ) { ..... }
@Transactional
@Secured({
"SAVINGS_ACCOUNT_CUSTOMER", "APPLICATION_ADMIN" })
public boolean
createFixedDeposit(FixedDepositDetails fixedDepositDetails) { ..... }
}
If you annotate a method
with Spring Security’s @Secured annotation, security feature
is transparently applied to the method by the Spring Security framework. The
above example listing shows that for implementing method-level security you don’t need to extend or implement any Spring-specific
classes or interfaces. Also, you don’t need to write security-related code in
your business methods.
Spring Security framework
is discussed in detail in chapter 16.
JMX (Java
Management Extensions)
Spring’s JMX support
simplifies incorporating JMX technology in your applications.
Let’s say that the fixed
deposit facility of MyBank
application should only be available to customers from 9:00 AM to 6:00 PM every
day. To address this requirement, a variable is added to the FixedDepositService
class, which acts as a flag indicating whether the fixed deposit service is
active or inactive. The following example listing shows the FixedDepositService
class that uses such a flag:
Example
listing 1-8 – FixedDepositService
with active
variable
public
class FixedDepositService {
private boolean active;
public FixedDepositDetails
getFixedDepositDetails( ..... ) {
if(active) { ..... }
}
public boolean
createFixedDeposit(FixedDepositDetails
fixedDepositDetails) {
if(active) { ..... }
}
public
void activateService() {
active = true;
}
public
void deactivateService() {
active = false;
}
}
The above example listing
shows that a variable named active is added to the FixedDepositService
class. If the value of the active variable is true,
the getFixedDepositDetails and createFixedDeposit
methods work as expected. If the value of the active
variable is false, the getFixedDepositDetails and createFixedDeposit
methods throw an exception indicating that the fixed deposit service is
currently inactive. The activateService and deactivateService
methods set the value of active variable to true
and false, respectively.
Now,
who calls the activateService
and deactivateService
methods? Let’s say a separate scheduler application, Bank App Scheduler, runs at 9:00 AM and 6:00 PM to execute activateService
and deactivateService methods,
respectively. The Bank App Scheduler application uses JMX (Java Management
Extensions) API to remotely interact with FixedDepositService
instance.
Refer
to the following article to learn more about JMX: http://docs.oracle.com/javase/tutorial/jmx/index.html.
As Bank App Scheduler uses
JMX to change the value of the active variable of the FixedDepositService
instance, you need to register the FixedDepositService
instance as a managed bean (or MBean) with an MBean
server, and expose FixedDepositService’s activateService
and deactivateService methods as JMX operations. In Spring,
you register instances of a class with the MBean server by annotating the class
with Spring’s @ManagedResource annotation, and expose the methods of the
class as JMX operations using Spring’s @ManagedOperation
annotation.
The following example
listing shows usage of @ManagedResource and @ManagedOperation
annotations to register instances of the FixedDepositService
class with the MBean server, and to expose its activateService and
deactivateService methods as JMX operations:
Example
listing 1-9 – FixedDepositService
class that uses Spring’s JMX support
import
org.springframework.jmx.export.annotation.ManagedOperation;
import
org.springframework.jmx.export.annotation.ManagedResource;
@ManagedResource(objectName
=
"fixed_deposit_service:name=FixedDepositService")
public
class FixedDepositService {
private boolean active;
public FixedDepositDetails
getFixedDepositDetails( ..... ) {
if(active) { ..... }
}
public boolean
createFixedDeposit(FixedDepositDetails
fixedDepositDetails) {
if(active) { ..... }
}
@ManagedOperation
public void activateService() {
active = true;
}
@ManagedOperation
public void deactivateService() {
active = false;
}
}
The
above example listing shows that the FixedDepositService
class doesn’t directly use JMX API to register its instances with the MBean
server and to expose its methods as JMX operations.
JMS (Java Message Service)
Spring’s JMS support simplifies sending and receiving messages from JMS
providers.
In MyBank application, when a customer submits a request to
receive details of their fixed deposits via email, the FixedDepositService
sends the request details to a JMS messaging middleware (like ActiveMQ). The request
is later processed by a message listener. Spring simplifies interaction with
JMS providers by providing a layer of abstraction. The following example
listing shows how FixedDepositService class sends
request details to a JMS provider using Spring’s JmsTemplate:
Example
listing 1-10 – FixedDepositService
that sends JMS messages
import
org.springframework.beans.factory.annotation.Autowired;
import
org.springframework.jms.core.JmsTemplate;
public
class FixedDepositService {
@Autowired
private
transient JmsTemplate jmsTemplate;
.....
public boolean submitRequest(Request
request) {
jmsTemplate.convertAndSend(request);
}
}
The above example listing
shows that the FixedDepositService defines a variable of type JmsTemplate,
and is annotated with Spring’s @Autowired annotation. For now,
you can assume that the @Autowired annotation provides access
to a JmsTemplate instance. The JmsTemplate
instance knows about the JMS destination to which the JMS message is to be sent.
The FixedDepositService’s submitRequest
method invokes JmsTemplate’s convertAndSend
method to send request details (represented by Request
argument of submitRequest method) as a JMS message to the JMS provider.
JmsTemplate
is discussed in detail in chapter 10.
Once again, the above
example listing shows that if you are using Spring Framework to send messages
to JMS providers, then you don’t need to directly deal with JMS API.
Caching
Spring’s cache abstraction
provides a consistent approach to use caching in your application.
It’s common to use caching
solutions to improve the performance of an application. MyBank application uses a caching product to improve the
performance of read operations for
fixed deposit details. Spring Framework simplifies interacting with different caching
solutions by abstracting caching-related logic.
The following example
listing shows that the FixedDepositService’s getFixedDepositDetails
method uses Spring’s cache abstraction feature to cache fixed deposit details:
Example
listing 1-11 – FixedDepositService
that caches fixed deposit details
import
org.springframework.cache.annotation.Cacheable;
public
class FixedDepositService {
@Cacheable("fixedDeposits")
public FixedDepositDetails
getFixedDepositDetails( ..... ) {
.....
}
public boolean
createFixedDeposit(FixedDepositDetails
fixedDepositDetails) { ..... }
}
In the above example
listing, Spring’s @Cacheable annotation indicates that
the fixed deposit details returned by the getFixedDepositDetails method are cached. If the getFixedDepositDetails method is invoked with the same
argument value(s), the getFixedDepositDetails method is not executed, and the fixed deposit details are returned from the
cache. This shows that if you are using Spring Framework, you don’t need to
write caching-related logic in your classes. Spring’s cache abstraction is
explained in detail in chapter 10.
In this section, we saw
that Spring Framework simplifies developing enterprise applications by
transparently providing services to POJOs, thereby shielding developers from
lower level API details. Spring also provides easy integration with standard
frameworks, like Hibernate, Quartz, JSF, Struts, EJB, and so on, which makes
Spring an ideal choice for enterprise application development.
Now that we have looked at
some of the benefits of using Spring Framework, let’s take a look at how to
develop a simple Spring application.
1-5
A simple Spring application
In this section, we’ll look
at a simple Spring application that uses Spring’s DI feature. To use Spring’s
DI feature in an application, follow these steps:
1.
identify application objects and their
dependencies
2.
create POJO classes corresponding to the
application objects identified in step 1
3. create configuration
metadata that depicts application objects and their dependencies
4. create an instance of Spring IoC container and
pass the configuration metadata to it
5.
access application objects from the Spring IoC
container instance
Let’s now look at above
mentioned steps in the context of MyBank application.
Identifying application objects and their dependencies
We
discussed earlier that the MyBank application shows a form for creating a fixed
deposit (refer figure 1-3). The following sequence diagram shows the
application objects (and their interaction) that come into picture when a user
submits the form:
Figure 1-4 MyBank’s application
objects and their dependencies
In the above sequence diagram,
FixedDepositController
represents a web controller that receives the request when the form is
submitted. The fixed deposit details are contained in the FixedDepositDetails
object. The FixedDepositController invokes the createFixedDeposit
method of FixedDepositService
(a service layer object). Then, FixedDepositService
invokes FixedDepositDao object (a data access object) to save the
fixed deposit details in the application’s data store. So, we can interpret
from the above diagram that FixedDepositService is a dependency of FixedDepositController
object, and FixedDepositDao is a dependency
of FixedDepositService object.
IMPORT chapter 1/ch01-bankapp-xml (This project shows a simple Spring application that uses Spring’s DI
feature. To run the application, execute the main method of the BankApp class of this project)
Creating
POJO classes corresponding to identified application objects
Once you have identified application
objects, the next step is to create POJO classes corresponding to these application
objects. POJO classes corresponding to the FixedDepositController,
FixedDepositService
and FixedDepositDao application objects are available in ch01-bankapp-xml
project. The ch01-bankapp-xml project represents a simplified version
of MyBank application that uses Spring’s DI feature. You should import the ch01-bankapp-xml
project into your IDE as in the remaining steps we’ll be looking at the files
contained in this project.
In section 1-3, we discussed that a dependency is passed to an
application object as a constructor argument or as a setter method argument. The following code listing shows that an
instance of FixedDepositService (a dependency of FixedDepositController) is passed as a setter method argument to
the FixedDepositController object:
Example listing 1-12
– FixedDepositController
class
Project – ch01-bankapp-xml
Source location
- src/main/java/sample/spring/chapter01/bankapp
package
sample.spring.chapter01.bankapp;
.....
public
class FixedDepositController {
.....
private FixedDepositService fixedDepositService;
.....
public void setFixedDepositService(FixedDepositService
fixedDepositService) {
logger.info("Setting
fixedDepositService property");
this.fixedDepositService = fixedDepositService;
}
.....
public void submit() {
fixedDepositService.createFixedDeposit(
new FixedDepositDetails( 1, 10000,
365, "someemail@something.com"));
}
.....
}
If you look at the
FixedDepositController, FixedDepositService and FixedDepositDao classes, you’ll notice
that none of these classes implement any Spring-specific interface or extend
from any Spring-specific class.
Let’s now look at how
application objects and their dependencies are specified in the configuration
metadata.
Creating
the configuration metadata
We saw in section 1-3 that
the configuration metadata specifies application objects and their
dependencies, which is read by the Spring container to instantiate application
objects and inject their dependencies. In this section, we’ll first look at
what other information is contained in the configuration metadata, followed by
an in-depth look at how configuration metadata is specified in XML format.
The configuration metadata
specifies information about the enterprise services (like transaction
management, security and remote access) that are required by the application.
For instance, if you want Spring to manage transactions, you need to configure
an implementation of Spring’s PlatformTransactionManager interface
in the configuration metadata. PlatformTransactionManager
implementation is responsible for managing transactions (refer chapter 8 to
know more about Spring’s transaction management feature).
If your application
interacts with messaging middlewares (like ActiveMQ), databases (like MySQL),
e-mail servers, and so on, then Spring-specific objects that simplify
interacting with these external systems are also defined in the configuration
metadata. For instance, if your application sends or receives JMS messages from
ActiveMQ, then you can configure Spring’s JmsTemplate
class in the configuration metadata to simplify interaction with ActiveMQ. We
saw in example listing 1-10 that if you use JmsTemplate
for sending messages to a JMS provider, then you don’t need to deal with
lower-level JMS API (refer chapter 10 to know more about Spring’s support for
interacting with JMS providers).
You can supply the
configuration metadata to the Spring container via an XML file or through
annotations in POJO classes. Starting with Spring 3.0, you can also supply the
configuration metadata to the Spring container through Java classes annotated
with Spring’s @Configuration annotation. In this section, we’ll see how
configuration metadata is specified in XML format. In chapters 6 and 7, we’ll
see how configuration metadata is supplied via annotations in POJO classes and
through @Configuration annotated Java classes, respectively.
You provide the
configuration metadata for an application in XML format by creating an application context XML file that
contains information about the application objects and their dependencies. Example
listing 1-3 showed how an application context XML file looks like. The
following XML shows the application context XML file of MyBank application that
consists of FixedDepositController, FixedDepositService
and FixedDepositDao objects (refer figure 1-4 to see how
these objects interact with each other):
Example
listing 1-13 – applicationContext.xml
- MyBank’s application context XML file
Project
– ch01-bankapp-xml
Source
location - src/main/resources/META-INF/spring
<?xml
version="1.0" encoding="UTF-8"
standalone="no"?>
<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.xsd">
<bean id="controller"
class="sample.spring.chapter01.bankapp.FixedDepositController">
<property name="fixedDepositService"
ref="service" />
</bean>
<bean id="service"
class="sample.spring.chapter01.bankapp.FixedDepositService">
<property
name="fixedDepositDao" ref="dao" />
</bean>
<bean id="dao"
class="sample.spring.chapter01.bankapp.FixedDepositDao"/>
</beans>
The following are the
important points to note about the application context XML file shown above:
> The <beans> element is the root element of the application
context XML file, and is defined in spring-beans.xsd
schema (also referred to as Spring’s beans schema).
The spring-beans.xsd schema is contained in spring-beans-5.0.1.RELEASE.jar
JAR file that comes with the Spring Framework 5.0.1.RELEASE distribution.
> Each <bean>
element configures an application object that is managed by the Spring container. In Spring
Framework’s terminology, a <bean> element represents a bean definition.
The object that the Spring container creates based on the bean definition is
referred to as a bean. The id
attribute specifies a unique name for the bean, and the class
attribute specifies the fully-qualified class name of the bean. You can also
use the name attribute of <bean>
element to specify aliases for the
bean. In MyBank application, the application objects are FixedDepositController,
FixedDepositService
and FixedDepositDao; therefore, we have 3 <bean>
elements - one for each application object. As application objects configured
by <bean> elements are managed by the Spring
container, the responsibility for creating them and injecting their
dependencies is with the Spring container. Instead of directly creating
instances of application objects defined by <bean>
elements, you should obtain them from the Spring container. Later in this
section, we’ll look at how to obtain application objects managed by Spring
container.
> No <bean>
element is defined
corresponding to the FixedDepositDetails domain object of MyBank application. This is
because domain objects are not
typically managed by the Spring container; they are created by the ORM
framework (like Hibernate) used by the application, or you create them
programmatically using the new operator.
·
The <property>
element specifies a dependency (or a configuration property) of
the bean configured by the <bean> element. The <property>
element corresponds to a JavaBean-style
setter method in the bean class which is invoked by the Spring container to
set a dependency (or a configuration property) of the bean.
Let’s now look at how dependencies
are injected via setter methods.
Injecting
dependencies via setter methods
To understand how
dependencies are injected via setter methods defined in the bean class, let’s once
again look at the FixedDepositController class of MyBank
application:
Example listing 1-14 – FixedDepositController class
Project
– ch01-bankapp-xml
Source
location - src/main/java/sample/spring/chapter01/bankapp
package
sample.spring.chapter01.bankapp;
import
org.apache.logging.log4j.LogManager;
import
org.apache.logging.log4j.Logger;
public
class FixedDepositController {
private static Logger logger =
LogManager.getLogger(FixedDepositController.class);
private FixedDepositService fixedDepositService;
public FixedDepositController() {
logger.info("initializing");
}
public void setFixedDepositService(FixedDepositService
fixedDepositService) {
logger.info("Setting
fixedDepositService property");
this.fixedDepositService = fixedDepositService;
}
.....
}
The above example listing
shows that the FixedDepositController class declares an instance
variable named fixedDepositService of type FixedDepositService.
The fixedDepositService variable is set by the setFixedDepositService
method - a JavaBean-style setter method
for fixedDepositService variable. This is an example of setter-based DI, wherein a setter method
satisfies a dependency.
Figure
1-5 describes the bean definition for the FixedDepositController
class in the applicationContext.xml file
(refer example listing 1-13).
Figure 1-5
Defining dependencies using <property>
elements
In
the context of FixedDepositController
application object, figure 1-6 summarizes the purpose of name
and ref
attributes of <property>
element.
The above bean definition
shows that the FixedDepositController bean defines its dependence on FixedDepositService
bean via <property> element. The <property>
element’s name attribute corresponds to the JavaBean-style setter
method in the bean class that is invoked by the Spring container at the time of
bean creation. The <property> element’s ref
attribute identifies the Spring bean whose instance needs to be created and
passed to the JavaBean-style setter method. The value of ref
attribute must match the id attribute’s value (or one of the
names specified by the name attribute) of a <bean>
element in the configuration metadata.
In figure 1-5, the value of
<property>
element’s name attribute is fixedDepositService,
which means that the <property> element corresponds
to the setFixedDepositService setter method of FixedDepositController
class (refer example listing 1-14). As the value of <property>
element’s ref attribute is service, the <property>
element refers to the <bean> element whose id
attribute’s value is service. Now, the <bean>
element whose id attribute’s value is service is the
FixedDepositService
bean (refer example listing 1-13). Spring container creates an instance of FixedDepositService
class (a dependency), and invokes the setFixedDepositService
method (a JavaBean-style setter method for fixedDepositService
variable) of FixedDepositController (a dependent object), passing the FixedDepositService
instance.
Figure 1-6
<property>
element’s name attribute corresponds to a JavaBean-style setter
method that satisfies a bean dependency, and ref attribute
refers to another bean.
The above figure shows that fixedDepositService value of name attribute
corresponds to the setFixedDepositService method of FixedDepositController class, and service value of ref attribute refers
to the bean whose id is service.
Figure
1-7 - The sequence in which Spring IoC container creates
beans and injects their dependencies.
It is fairly common to refer to a bean
definition by its name (which is id attribute’s value) or type (which is class attribute’s
value) or the interface implemented by the bean class. For instance, you can
refer to 'FixedDepositController bean' as 'controller bean'. And, if
the FixedDepositController class implements FixedDepositControllerIntf interface,
you can refer to 'FixedDepositController bean' as 'FixedDepositControllerIntf bean'.
The bean definitions that
we have seen so far, instruct Spring container to create bean instances by
invoking the no-argument constructor
of the bean class, and inject dependencies using setter-based DI. In chapter 2,
we’ll look at bean definitions that instruct Spring container to create a bean
instance via a factory method defined
in a class. Also, we’ll look at how to inject dependencies through constructor
arguments (referred to as constructor-based
DI).
Let’s now look at how to
create an instance of Spring container and pass configuration metadata to it.
Creating
an instance of Spring container
Spring’s ApplicationContext
object represents an instance of Spring container. Spring provides a few
built-in implementations of ApplicationContext interface, like ClassPathXmlApplicationContext,
FileSystemXmlApplicationContext,
XmlWebApplicationContext,
and so on. The choice of the ApplicationContext
implementation depends on how you have defined the configuration metadata
(using XML, annotations or Java code), and the type of your application
(standalone or web). For instance, ClassPathXmlApplicationContext
and FileSystemXmlApplicationContext classes are suitable for standalone applications in which
configuration metadata is supplied in XML format, XmlWebApplicationContext
is suitable for web applications in
which the configuration metadata is supplied in XML format, AnnotationConfigWebApplicationContext
is suitable for web applications in
which configuration metadata is supplied programmatically through Java code,
and so on.
As MyBank application represents a standalone
application, we can use either ClassPathXmlApplicationContext or FileSystemXmlApplicationContext class to create an instance of Spring
container. You should note that the ClassPathXmlApplicationContext class loads an application context XML file from the
specified classpath location, and the FileSystemXmlApplicationContext class loads an application context
XML file from the specified location on the filesystem.
The following BankApp
class of MyBank application shows that an instance of Spring container is
created using the ClassPathXmlApplicationContext class:
Example
listing 1-15 – BankApp
class
Project
– ch01-bankapp-xml
Source
location - src/main/java/sample/spring/chapter01/bankapp
package
sample.spring.chapter01.bankapp;
import
org.springframework.context.ApplicationContext;
import
org.springframework.context.support.ClassPathXmlApplicationContext;
public
class BankApp {
.....
public static void main(String args[]) {
ApplicationContext context = new
ClassPathXmlApplicationContext(
"classpath:META-INF/spring/applicationContext.xml");
.....
}
}
The above example listing
shows the BankApp’s main method, which is responsible
for bootstrapping the Spring container. The classpath location of the application
context XML file is passed to the constructor of ClassPathXmlApplicationContext
class. The creation of ClassPathXmlApplicationContext
instance results in creation of those beans in the application context XML file
that are singleton-scoped and set to
be pre-instantiated. In chapter 2,
we’ll discuss bean scopes, and what
it means to have beans pre- or lazily-instantiated by Spring container.
For now, you can assume that the beans defined in the applicationContext.xml
file of MyBank application are singleton-scoped and set to be pre-instantiated.
This means that the beans defined in the applicationContext.xml
file are created when an instance of ClassPathXmlApplicationContext
is created.
Now that we have seen how
to create an instance of the Spring container, let’s look at how to retrieve
bean instances from the Spring container.
Access
beans from the Spring container
The application objects
defined via <bean> elements are created and managed by the
Spring container. You can access instances of these application objects by
calling one of the getBean methods of the ApplicationContext
interface.
The following example
listing shows the main method of BankApp class
that retrieves an instance of FixedDepositController bean
from the Spring container and invokes its methods:
Example
listing 1-16 – BankApp
class
Project
– ch01-bankapp-xml
Source
location - src/main/java/sample/spring/chapter01/bankapp
package
sample.spring.chapter01.bankapp;
import org.apache.logging.log4j.LogManager;
import
org.apache.logging.log4j.Logger;
import
org.springframework.context.ApplicationContext;
import
org.springframework.context.support.ClassPathXmlApplicationContext;
public
class BankApp {
private static Logger logger =
LogManager.getLogger(BankApp.class);
public static void main(String args[]) {
ApplicationContext
context = new
ClassPathXmlApplicationContext(
"classpath:META-INF/spring/applicationContext.xml");
FixedDepositController
fixedDepositController =
(FixedDepositController)
context.getBean("controller");
logger.info("Submission status of
fixed deposit : "
+
fixedDepositController.submit());
logger.info("Returned fixed
deposit info : " +
fixedDepositController.get());
}
}
At first, the ApplicationContext’s getBean method is invoked to retrieve an instance of FixedDepositController bean from the Spring container, followed by invocation of submit and get methods of FixedDepositController bean. The argument passed to the getBean method is the name of the bean whose instance you want to retrieve from the Spring container. The name of the bean passed to the getBean method must be the value of the id or name attribute of the bean that you want to retrieve. If no bean with the specified name is registered with the Spring container, an exception is thrown by the getBean method.
In example listing 1-16, to configure the FixedDepositController instance, we didn’t programmatically create an instance of FixedDepositService and set it on the FixedDepositController instance. Also, we didn’t create an instance of FixedDepositDao and set it on the FixedDepositService instance. This is because the task of creating dependencies, and injecting them into the dependent objects is handled by the Spring container.
If you go
to ch01-bankapp-xml project and execute the main
method of BankApp class, you’ll see the following output on the
console:
INFO
sample.spring.chapter01.bankapp.FixedDepositController - initializing
INFO
sample.spring.chapter01.bankapp.FixedDepositService - initializing
INFO
sample.spring.chapter01.bankapp.FixedDepositDao - initializing
INFO
sample.spring.chapter01.bankapp.FixedDepositService - Setting
fixedDepositDao property
INFO
sample.spring.chapter01.bankapp.FixedDepositController - Setting
fixedDepositService property
INFO
sample.spring.chapter01.bankapp.BankApp - Submission status of fixed
deposit : true
INFO sample.spring.chapter01.bankapp.BankApp -
Returned fixed deposit info : id :1, deposit amount : 10000.0, tenure : 365,
email : someemail@something.com
The above output shows that the Spring container creates an instance of each of the beans defined in the applicationContext.xml file of MyBank application. Also, Spring container uses setter-based DI to inject an instance of FixedDepositService into FixedDepositController instance, and an instance of FixedDepositDao into the FixedDepositService instance.
Spring
Framework 5 introduces many new interesting features and enhancements. Let’s
look at some of the important changes to Spring Framework 5.
1-6 What’s new in Spring Framework 5 ?
1-6 What’s new in Spring Framework 5 ?
The following are some of the notable changes to Spring
Framework 5 release:
> compatible
with Java 9. This means you can develop applications using Java 9 features and
deploy them on Java 9.
>
Spring
Framework JARs can be added to Java 9’s module
path or classpath. If you add Spring Framework JARs to the module path,
they are converted into automatic modules
that export all their packages.
>
embraces
reactive programming paradigm for
developing asynchronous and non-blocking applications. Spring
supports using reactive types defined
by Reactor 3.1 and RxJava 1.3 and 2.1 libraries. Chapter 18 and 19 discuss
developing reactive applications using RxJava 2 and Reactor 3.1.
>
source
code of the Spring Framework 5 itself is now based on Java 8
>
the
support for portlets, Velocity templates and JasperReports has been dropped
from Spring Framework 5
>
@Nullable, @NonNull, @NonNullApi and @NonNullFields annotations bring
null-safety to Spring applications.
@Nullable
annotation indicates that a field, method argument or a method’s return value can be null. @NonNull annotation indicates that a
field, method argument or a method’s return value cannot be null. @NonNullApi is a package-level
annotation that specifies that the methods and their parameters cannot be null. @NonNullFields is a package-level
annotation that specifies that the fields cannot
be null. These annotations can be
used by static code analysis tools (like FindBugs) to highlight potential
issues in the program that can cause java.lang.NullPointerException at runtime.
>
functional
style bean registration and customization using the newly introduced methods in
AnnotationConfigApplicationContext class (refer chapter 7 for more details)
> generating
and reading an index of Spring components from a file (instead of classpath
scanning) for faster application startup (refer chapter 7 for more details)
>
support
for Servlet 4.0’s javax.servlet.http.PushBuilder as a controller method
argument in Spring Web MVC applications. PushBuilder allows pushing resources to
web clients using HTTP/2 protocol.
>
a
new web module, spring-webflux, for developing reactive web applications and RESTful
web services using RxJava and Reactor libraries (covered in chapters 18 and
19).
>
AsyncRestTemplate support is deprecated in
favor of the reactive WebClient (chapter 19 shows how you
can use WebClient to access a RESTful web
service in a functional and reactive style)
Let’s now look at some of the frameworks that are built on
top of Spring Framework.
1-7 Frameworks built on top of Spring
Though there are many frameworks that use Spring Framework
as the foundation, we’ll look at some of the widely popular ones. For a more
comprehensive list of frameworks, and for more details about an individual
framework, it’s recommended that you visit https://spring.io/projects.
1-8 Summary
1-7 Frameworks built on top of Spring
Though there are many frameworks that use Spring Framework
as the foundation, we’ll look at some of the widely popular ones. For a more
comprehensive list of frameworks, and for more details about an individual
framework, it’s recommended that you visit https://spring.io/projects.
As Spring Framework 5 embraces reactive programming paradigm,
the framework built on top of Spring have also undergone changes to support
developing reactive applications.
The following table provides a high-level
overview of the frameworks that are built on top of Spring Framework:
As the frameworks mentioned in the above table
are built on top of Spring Framework, before using any of these frameworks make
sure that they are compatible with the Spring Framework version that you are
using.
1-8 Summary
In
this chapter, we looked at the benefits of using Spring Framework. We also looked
at a simple Spring application that showed how to specify configuration
metadata in XML format, create the Spring container instance and retrieve beans
from it. In the next chapter, we’ll look at some of the foundation concepts of
Spring Framework.
Comments
Post a Comment