Spring 5 Design Patterns

5 (2 reviews total)
By Dinesh Rajput
  • Instant online access to over 7,500+ books and videos
  • Constantly updated with 100+ new titles each month
  • Breadth and depth in over 1,000+ technologies
  1. Getting Started with Spring Framework 5.0 and Design Patterns

About this book

Design patterns help speed up the development process by offering well tested and proven solutions to common problems. These patterns coupled with the Spring framework offer tremendous improvements in the development process.

The book begins with an overview of Spring Framework 5.0 and design patterns. You will understand the Dependency Injection pattern, which is the main principle behind the decoupling process that Spring performs, thus making it easier to manage your code. You will learn how GoF patterns can be used in Application Design. You will then learn to use Proxy patterns in Aspect Oriented Programming and remoting. Moving on, you will understand the JDBC template patterns and their use in abstracting database access. Then, you will be introduced to MVC patterns to build Reactive web applications. Finally, you will move on to more advanced topics such as Reactive streams and Concurrency.

At the end of this book, you will be well equipped to develop efficient enterprise applications using Spring 5 with common design patterns

Publication date:
October 2017
Publisher
Packt
Pages
396
ISBN
9781788299459

 

Chapter 1. Getting Started with Spring Framework 5.0 and Design Patterns

This chapter will help you gain a better understanding of the Spring Framework with modules, and use the design patterns that are responsible for the success of Spring. This chapter will cover every major module of the Spring Framework. We begin with an introduction to the Spring Framework. We will have a look at the new features and enhancement introduced in Spring 5. We will also understand the design patterns used in the major modules of the Spring Framework.

At the end of this chapter, you will understand how Spring works, and how Spring solves the common problems of the design level of the enterprise application by using design patterns. You will know how to improve loose coupling between the components of applications and how to simplify application development by using Spring with design patterns.

This chapter will cover the following topics:

  • Introduction of the Spring Framework
  • Simplifying application development using Spring and its pattern
    • Using the power of the POJO pattern
    • Injecting dependencies
    • Applying aspects to address cross-cutting concerns
    • Applying a template pattern to eliminate boilerplate code
  • Creating a Spring container for containing beans using the Factory pattern
    • Creating a container with an application context
    • The life of a bean in the container
  • Spring modules
  • New features in Spring Framework 5.0
 

Introducing Spring Framework


In the early days of Java, there were lots of heavier enterprise Java technologies for enterprise applications that provided enterprise solutions to programmers. However, it was not easy to maintain the applications because it was tightly coupled with the framework. A couple of years ago, apart from Spring, all Java technologies were heavier, like EJB. At the time, Spring was introduced as an alternative technology especially made for EJB because Spring provided a very simple, leaner, and lighter programming model compared with other existing Java technologies. Spring makes this possible by using many available design patterns, but it focused on the Plain Old Java Object (POJO) programming model. This model provided the simplicity to the Spring Framework. It also empowered ideas such as the dependency injection (DI) pattern and Aspect-Oriented Programming (AOP) by using the Proxy pattern and Decorator pattern.

The Spring Framework is an open source application framework and a Java-based platform that provides comprehensive infrastructure support for developing enterprise Java applications. So developers don't need to care about the infrastructure of the application; they should be focused on the business logic of the application rather than handling the configuration of the application. All infrastructure, configuration, and meta-configuration files, either Java-based configuration or XML-based configuration, both are handled by the Spring Framework. So this framework makes you more flexible in building an application with a POJOs programming model rather than a non-invasive programming model.

The Spring Inversion of Control (IoC) container is the heart of the entire framework. It helps glue together the different parts of the application, thus forming a coherent architecture. Spring MVC components can be used to build a very flexible web tier. The IOC container simplifies the development of the business layer with POJOs.

Spring simplifies the application development and removes a lot of the dependency on the other APIs. Let's see some examples of how you, as an application developer, can benefit from the Spring platform:

  • All application classes are simple POJO classes--Spring is not invasive. It does not require you to extend framework classes or implement framework interfaces for most use cases.
  • Spring applications do not require a Java EE application server, but they can be deployed on one.
  • You can execute a method in a database transaction by using transaction management in Spring Framework without having any third-party transactional API.
  • Using Spring, you can use a Java method as a request handler method or remote method, like a service() method of a servlet API, but without dealing with the servlet API of the servlet container.
  • Spring enables you to use a local java method as a message handler method without using a Java Message Service (JMS) API in the application.
  • Spring also enables you to use the local java method as a management operation without using a Java Management Extensions (JMX) API in the application.
  • Spring serves as a container for your application objects. Your objects do not have to worry about finding and establishing connections with each other.
  • Spring instantiates the beans and injects the dependencies of your objects into the application--it serves as a life cycle manager of the beans.
 

Simplifying application development using Spring and its pattern


Developing an enterprise application using the traditional Java platform has a lot of limitations when it comes to organizing the basic building blocks as individual components for reusability in your application. Creating reusable components for basic and common functionality is best design practice, so you cannot ignore it. To address the reusability problem in your application, you can use various design patterns, such as the Factory pattern, Abstract Factory pattern, Builder pattern, Decorator pattern, and Service Locator pattern, to compose the basic building blocks into a coherent whole, such as class and object instances, to promote the reusability of components. These patterns address the common and recursive application problems. Spring Framework simply implements these patterns internally, providing you with an infrastructure to use in a formalized way.

There are lots of complexities in enterprise application development, but Spring was created to address these, and makes it possible to simplify the process for developers. Spring isn't only limited to server-side development--it also helps simplifies things regarding building projects, testability, and loose coupling. Spring follows the POJO pattern, that is, a Spring component can be any type of POJO. A component is a self-contained piece of code that ideally could be reused in multiple applications.

Since this book is focused on all design patterns that are adopted by the Spring Framework to simplify Java development, we need to discuss or at least provide some basic implementation and consideration of design patterns and the best practices to design the infrastructure for enterprise application development. Spring uses the following strategies to make java development easy and testable:

  • Spring uses the power of the POJO pattern for lightweight and minimally invasive development of enterprise applications
  • It uses the power of the dependency injection pattern (DI pattern) for loose coupling and makes a system interface oriented
  • It uses the power of the Decorator and Proxy design pattern for declarative programming through aspects and common conventions
  • It uses the power of the Template Design pattern for eliminating boilerplate code with aspects and templates

In this chapter, I'll explain each of these ideas, and also show concrete examples of how Spring simplifies Java development. Let's start with exploring how Spring remains minimally invasive by encouraging POJO-oriented development by using the POJO pattern.

Using the power of the POJO pattern

There are many other frameworks for Java development that lock you in by forcing you to extend or implement one of their existing classes or interfaces; Struts, Tapestry, and earlier versions of EJB had this approach. The programming model of these frameworks is based on the invasive model. This makes it harder for your code to find bugs in the system, and sometimes it will render your code unintelligible. However, if you are working with Spring Framework, you don't need to implement or extend its existing classes and interfaces, so this is simply POJO-based implementation, following a non-invasive programming model. It makes it easier for your code to find bugs in the system, and keeps the code understandable.

Spring allows you to do programming with very simple non Spring classes, which means there is no need to implement Spring-specific classes or interfaces, so all classes in the Spring-based application are simply POJOs. That means you can compile and run these files without dependency on Spring libraries; you cannot even recognize that these classes are being used by the Spring Framework. In Java-based configuration, you will use Spring annotations, which is the worst case of the Spring-based application.

Let's look at this with the help of the following example:

    package com.packt.chapter1.spring; 
    public class HelloWorld { 
      public String hello() { 
        return "Hello World"; 
      } 
    } 

The preceding class is a simple POJO class with no special indication or implementation related to the framework to make it a Spring component. So this class could function equally well in a Spring application as it could in a non-Spring application. This is the beauty of Spring's non-invasive programming model. Another way that Spring empowers POJO is by collaborating with other POJOs using the DI pattern. Let's see how DI works to help decouple components.

Injecting dependencies between POJOs

The term dependency injection is not new-it is used by PicoContainer. Dependency injection is a design pattern that promotes loose coupling between the Spring components--that is, between the different collaborating POJOs. So by applying DI to your complex programming, your code will become simpler, easier to understand, and easier to test.

In your application, many objects are working together for a particular functionality as per your requirement. This collaboration between the objects is actually known as dependency injection. Injecting dependency between the working components helps you to unit test every component in your application without tight coupling.

In a working application, what the end user wants is to see the output. To create the output, a few objects in the application work together and are sometimes coupled. So when you are writing these complex application classes, consider the reusability of these classes and make these classes as independent as possible. This is a best practice of coding that will help you in unit testing these classes independently.

How DI works and makes things easy for development and testing

Let's look at DI pattern implementation in your application. It makes things easy to understand, loosely coupled, and testable across the application. Suppose we have a simple application (something more complex than a Hello World example that you might make in your college classes). Every class is working together to perform some business task and help build business needs and expectations. That means that each class in the application has its measure of responsibility for a business task, together with other collaborating objects (its dependencies). Let's look at the following image. This dependency between the objects can create complexity and tight coupling between the dependent objects:

The TransferService component is traditionally dependent on two other components: TransferRepository and AccountRepository

A typical application system consists of several parts working together to carry out a use case. For example, consider the TransferService class, shown next.

TransferService using direct instantiation:

    package com.packt.chapter1.bankapp.transfer; 
    public class TransferService { 
      private AccountRepository accountRepository; 
      public TransferService () { 
        this.accountRepository = new AccountRepository(); 
      } 
      public void transferMoney(Account a, Account b) { 
        accountRepository.transfer(a, b); 
      } 
    } 

The TransferService object needs an AccountRepository object to make money transfer from account a to account b. Hence, it creates an instance of the AccountRepository object directly and uses it. But direct instantiation increases coupling and scatters the object creation code across the application, making it hard to maintain and difficult to write a unit test for TransferService, because, in this case, whenever you want to test the transferMoney() method of the TransferService class by using the assert to unit test, then the transfer() method of the AccountRepository class is also called unlikely by this test. But the developer is not aware about the dependency of AccountRepository on the TransferService class; at least, the developer is not able to test the transferMoney() method of the TransferService class using unit testing.

In enterprise applications, coupling is very dangerous, and it pushes you to a situation where you will not be able to do any enhancement in the application in the future, where any further changes in such an application can create a lot of bugs, and where fixing these bugs can create new bugs. Tightly coupled components are one of the reasons for major problems in these applications. Unnecessary tightly coupled code makes your application non-maintainable, and as time goes by, its code will not be reused, as it cannot be understood by other developers. But sometimes a certain amount of coupling is required for an enterprise application because completely uncoupled components are not possible in real-world cases. Each component in the application has some responsibility for a role and business requirement, to the extent that all components in the application have to be aware of the responsibility of the other components. That means coupling is necessary sometimes, but we have to manage the coupling between required components very carefully.

Using factory helper pattern for dependent components

Let's try another method for dependent objects using the Factory pattern. This design pattern is based on the GOF factory design pattern to create object instances by using a factory method. So this method actually centralizes the use of the new operator. It creates the object instances based on the information provided by the client code. This pattern is widely used in the dependency injection strategy.

TransferService using factory helper:

    package com.packt.chapter1.bankapp.transfer; 
    public class TransferService { 
      private AccountRepository accountRepository; 
      public TransferService() { 
        this.accountRepository = 
          AccountRepositoryFactory.getInstance("jdbc"); 
      } 
      public void transferMoney(Account a, Account b) { 
        accountRepository.transfer(a, b); 
      } 
    } 

In the preceding code, we use the Factory pattern to create an object of AccountRepository. In software engineering, one of the best practices of application design and development is program-to-interface (P2I). According to this practice, concrete classes must implement an interface that is used in the client code for the caller rather than using a concrete class. By using P2I, you can improve the preceding code. Therefore, we can easily replace it with a different implementation of the interface with little impact on the client code. So programming-to-interface provides us with a method involving low coupling. In other words, there is no direct dependency on a concrete implementation leading to low coupling. Let's look at the following code. Here, AccountRepository is an interface rather than a class:

    public interface AccountRepository{ 
      void transfer(); 
      //other methods 
    } 

So we can implement it as per our requirement, and it is dependent upon the client's infrastructure. Suppose we want an AccountRepository during the development phase with JDBC API. We can provide a JdbcAccountRepositry concrete implementation of the AccountRepositry interface, as shown here:

    public class JdbcAccountRepositry implements AccountRepositry{ 
      //...implementation of methods defined in AccountRepositry 
      // ...implementation of other methods 
    } 

In this pattern, objects are created by factory classes to make it easy to maintain, and this avoids scattering the code of object creation across other business components. With a factory helper, it is also possible to make object creation configurable. This technique provides a solution for tight coupling, but we are still adding factory classes to the business component for fetching collaborating components. So let's see the DI pattern in the next section and look at how to solve this problem.

Using DI pattern for dependent components

According to the DI pattern, dependent objects are given their dependencies at the time of the creation of the objects by some factory or third party. This factory coordinates each object in the system in such a way that each dependent object is not expected to create their dependencies. This means that we have to focus on defining the dependencies instead of resolving the dependencies of collaborating objects in the enterprise application. Let's look at the following image. You will learn that dependencies are injected into the objects that need them:

Dependency injection between the different collaborating components in the application

To illustrate this point, let's look at TransferService in the next section--a TransferService has dependency with AccountRepository and TransferRepository. Here, TransferService is capable of transferring money by any kind implementation of TransferRepository, that is, we can either use JdbcTransferRepository or JpaTransferRepository, depending on whichever comes along according to the deployment environment.

TransferServiceImpl is flexible enough to take on any TransferRepository it's given:

    package com.packt.chapter1.bankapp; 
    public class TransferServiceImpl implements TransferService { 
      private TransferRepository transferRepository; 
      private AccountRepository  accountRepository; 
      public TransferServiceImpl(TransferRepository transferRepository,
       AccountRepository  accountRepository) { 
         this.transferRepository =
          transferRepository;//TransferRepository is injected 
         this.accountRepository  = accountRepository; 
         //AccountRepository is injected 
       } 
       public void transferMoney(Long a, Long b, Amount amount) { 
         Account accountA = accountRepository.findByAccountId(a); 
         Account accountB = accountRepository.findByAccountId(b); 
         transferRepository.transfer(accountA, accountB, amount); 
       } 
    } 

Here you can see that TransferServiceImpl doesn't create its own repositories implementation. Instead, we have given the implementation of repositories at the time of construction as a constructor argument. This is a type of DI known as constructor injection. Here we have passed the repository interface type as an argument of the constructor. Now TransferServiceImpl could use any implementation of repositories, either JDBC, JPA, or mock objects. The point is that TransferServiceImpl isn't coupled to any specific implementation of repositories. It doesn't matter what kind of repository is used to transfer an amount from one account to another account, as long as it implements the repositories interfaces. If you are using the DI pattern of the Spring Framework, loose coupling is one of the key benefits. The DI pattern always promotes P2I, so each object knows about its dependencies by their associated interface rather than associated implementation, so the dependency can easily be swapped out with another implementation of that interface instead of changing to its dependent class implementation.

Spring provides support for assembling such an application system from its parts:

  • Parts do not worry about finding each other
  • Any part can easily be swapped out

The method for assembling an application system by creating associations between application parts or components is known as wiring. In Spring, there are many ways to wire collaborating components together to make an application system. For instance, we could use either an XML configuration file or a Java configuration file.

Now let's look at how to inject the dependencies of TransferRepository and AccountRepository into a TransferService with Spring:

    <?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.xsd"> 
    <bean id="transferService"  
     class="com.packt.chapter1.bankapp.service.TransferServiceImpl"> 
         <constructor-arg ref="accountRepository"/> 
         <constructor-arg ref="transferRepository"/> 
    </bean> 
    <bean id="accountRepository" class="com.
     packt.chapter1.bankapp.repository.JdbcAccountRepository"/> 
    <bean id="transferRepository" class="com.  
     packt.chapter1.bankapp.repository.JdbcTransferRepository"/>     
    
    </beans> 

Here, TransferServiceImpl, JdbcAccountRepository, and JdbcTransferRepository are declared as beans in Spring. In the case of the TransferServiceImpl bean, it's constructed, passing a reference to the AccountRepository and TransferRepository beans as constructor arguments. You might like to know that Spring also allows you to express the same configuration using Java.

Spring offers Java-based configuration as an alternative to XML:

    package com.packt.chapter1.bankapp.config; 
 
    import org.springframework.context.annotation.Bean; 
    import org.springframework.context.annotation.Configuration; 
 
    import com.packt.chapter1.bankapp.repository.AccountRepository; 
    import com.packt.chapter1.bankapp.repository.TransferRepository; 
    import 
     com.packt.chapter1.bankapp.repository.jdbc.JdbcAccountRepository; 
    import 
     com.packt.chapter1.bankapp.repository.jdbc.JdbcTransferRepository; 
    import com.packt.chapter1.bankapp.service.TransferService; 
    import com.packt.chapter1.bankapp.service.TransferServiceImpl; 
 
    @Configuration 
    public class AppConfig { 
    
     @Bean 
     public TransferService transferService(){ 
       return new TransferServiceImpl(accountRepository(),
       transferRepository()); 
     } 
     @Bean 
     public AccountRepository accountRepository() { 
       return new JdbcAccountRepository(); 
     } 
     @Bean 
     public TransferRepository transferRepository() { 
       return new JdbcTransferRepository(); 
     } 
    } 

The benefits of the dependency injection pattern are the same whether you are using an XML-based or a Java-based configuration:

  • Dependency injection promotes loose coupling. You can remove hard-coded dependencies with best practice P2I, and you could provide dependencies from outside the application by using the Factory pattern and its built-in swappable and pluggable implementation
  • The DI pattern promotes the composition design of object-oriented programming rather than inheritance programming

Although TransferService depends on an AccountRepository and TransferRepository, it doesn't care about what type (JDBC or JPA) of implementations of AccountRepository and TransferRepository are used in the application. Only Spring, through its configuration (XML- or Java-based), knows how all the components come together and are instantiated with their required dependencies using the DI pattern. DI makes it possible to change those dependencies with no changes to the dependent classes--that is, we could use either a JDBC implementation or a JPA implementation without changing the implementation of AccountService.

In a Spring application, an implementation of the application context (Spring offers AnnotationConfigApplicationContext for Java-based and ClassPathXmlApplicationContext for XML-based implementations) loads bean definitions and wires them together into a Spring container. The application context in Spring creates and wires the Spring beans for the application at startup. Look into the implementation of the Spring application context with Java-based configuration--It loads the Spring configuration files (AppConfig.java for Java and Sprig.xml for XML) located in the application's classpath. In the following code, the main() method of the TransferMain class uses a AnnotationConfigApplicationContext class to load the configuration class AppConfig.java and get an object of the AccountService class.

Spring offers Java-based configuration as an alternative to XML:

    package com.packt.chapter1.bankapp; 
 
    import org.springframework.context.ConfigurableApplicationContext; 
    import 
     org.springframework.context.annotation
     .AnnotationConfigApplicationContext; 
 
    import com.packt.chapter1.bankapp.config.AppConfig; 
    import com.packt.chapter1.bankapp.model.Amount; 
    import com.packt.chapter1.bankapp.service.TransferService; 
 
    public class TransferMain { 
 
      public static void main(String[] args) { 
        //Load Spring context 
        ConfigurableApplicationContext applicationContext = 
          new AnnotationConfigApplicationContext(AppConfig.class); 
         //Get TransferService bean 
         TransferService transferService = 
          applicationContext.getBean(TransferService.class); 
           //Use transfer method 
         transferService.transferAmmount(100l, 200l,
          new Amount(2000.0)); 
         applicationContext.close(); 
      } 
 
    }    

Here we have a quick introduction to the dependency injection pattern. You'll learn a lot more about the DI pattern in the coming chapters of this book. Now let's look at another way of simplifying Java development using Spring's declarative programming model through aspects and proxy patterns.

Applying aspects for cross cutting concerns

In a Spring application, the DI pattern provides us with loose coupling between collaborating software components, but Aspect-Oriented Programming in Spring (Spring AOP) enables you to capture common functionalities that are repetitive throughout your application. So we can say that Spring AOP promotes loose coupling and allows cross-cutting concerns, listed as follows, to be separated in a most elegant fashion. It allows these services to be applied transparently through declaration. With Spring AOP, it is possible to write custom aspects and configure them declaratively.

The generic functionalities that are needed in many places in your application are:

  • Logging and tracing
  • Transaction management
  • Security
  • Caching
  • Error handling
  • Performance monitoring
  • Custom business rules

The components listed here are not part of your core application, but these components have some additional responsibilities, commonly referred to as cross-cutting concerns because they tend to cut across multiple components in a system beyond their core responsibilities. If you put these components with your core functionalities, thereby implementing cross-cutting concerns without modularization, it will have two major problems:

  • Code tangling: A coupling of concerns means that a cross-cutting concern code, such as a security concern, a transaction concern, and a logging concern, is coupled with the code for business objects in your application.
  • Code scattering: Code scattering refers to the same concern being spread across modules. This means that your concern code of security, transaction, and logging is spread across all modules of the system. In other words, you can say there is a duplicity of the same concern code across the system.

The following diagram illustrates this complexity. The business objects are too intimately involved with the cross-cutting concerns. Not only does each object know that it's being logged, secured, and involved in a transactional context, but each object is also responsible for performing those services assigned only to it:

Cross-cutting concerns, such as logging, security and transaction, are often scattered about in modules where those tasks are not their primary concern

Spring AOP enables the modularization of cross-cutting concerns to avoid tangling and scattering. You can apply these modularized concerns to the core business components of the application declaratively without affecting the aforementioned the above components. The aspects ensure that the POJOs remain plain. Spring AOP makes this magic possible by using the Proxy Design Pattern. We will discuss the Proxy Design pattern more in the coming chapters of this book.

How Spring AOP works

The following points describe the work of Spring AOP:

  • Implement your mainline application logic: Focusing on the core problem means that, when you are writing the application business logic, you don't need to worry about adding additional functionalities, such as logging, security, and transaction, between the business codes-Spring AOP takes care of it.
  • Write aspects to implement your cross-cutting concerns: Spring provides many aspects out of the box, which means you can write additional functionalities in the form of the aspect as independent units in Spring AOP. These aspects have additional responsibilities as cross-cutting concerns beyond the application logic codes.
  • Weave the aspects into your application: Adding the cross-cutting behaviors to the right places, that is, after writing the aspects for additional responsibilities, you could declaratively inject them into the right places in the application logic codes.

Let's look at an illustration of AOP in Spring:

AOP-based system evolution--this leaves the application components to focus on their specific business functionalities

In the preceding diagram, Spring AOP separates the cross-cutting concerns, for example, security, transaction, and logging, from the business modules, that is, BankService, CustomerService, and ReportingService. These cross-cutting concerns are applied to predefined points (stripes in the preceding diagram) of the business modules at the running time of the application.

Suppose that you want to log the messages before and after calling the transferAmmount() method of TransferService using the services of a LoggingAspect. The following listing shows the LoggingAspect class you might use.

LoggingAspect call is used for logging the system for TransferService:

    package com.packt.chapter1.bankapp.aspect; 
 
    import org.aspectj.lang.annotation.After; 
    import org.aspectj.lang.annotation.Aspect; 
    import org.aspectj.lang.annotation.Before; 
 
    @Aspect 
    public class LoggingAspect { 
    
     @Before("execution(* *.transferAmount(..))") 
     public void logBeforeTransfer(){ 
       System.out.println("####LoggingAspect.logBeforeTransfer() 
       method called before transfer amount####"); 
     } 
    
     @After("execution(* *.transferAmount(..))") 
     public void logAfterTransfer(){ 
       System.out.println("####LoggingAspect.logAfterTransfer() method
       called after transfer amount####"); 
     } 
    } 

To turn LoggingAspect into an aspect bean, all you need to do is declare it as one in the Spring configuration file. Also, to make it an aspect, you have to add the @Aspect annotation to this class. Here's the updated AppConfig.java file, revised to declare LoggingAspect as an aspect.

Declaring LoggingAspect as an aspect and enabling the Apsect proxy feature of Spring AOP:

    package com.packt.chapter1.bankapp.config; 
 
    import org.springframework.context.annotation.Bean; 
    import org.springframework.context.annotation.Configuration; 
    import
     org.springframework.context.annotation.EnableAspectJAutoProxy; 
 
    import com.packt.chapter1.bankapp.aspect.LoggingAspect; 
    import com.packt.chapter1.bankapp.repository.AccountRepository; 
    import com.packt.chapter1.bankapp.repository.TransferRepository; 
    import
     com.packt.chapter1.bankapp.repository.jdbc.JdbcAccountRepository; 
    import
     com.packt.chapter1.bankapp.repository.jdbc.JdbcTransferRepository; 
    import com.packt.chapter1.bankapp.service.TransferService; 
    import com.packt.chapter1.bankapp.service.TransferServiceImpl; 
 
    @Configuration 
    @EnableAspectJAutoProxy 
    public class AppConfig { 
    
      @Bean 
      public TransferService transferService(){ 
        return new TransferServiceImpl(accountRepository(),
        transferRepository()); 
      } 
      @Bean 
      public AccountRepository accountRepository() { 
        return new JdbcAccountRepository(); 
      } 
      @Bean 
      public TransferRepository transferRepository() { 
        return new JdbcTransferRepository(); 
      } 
      @Bean 
      public LoggingAspect loggingAspect() { 
        return new LoggingAspect(); 
      } 
    } 

Here, we're using Spring's AOP configuration based on Java to declare the LoggingAspect bean as an aspect. First, we declare LoggingAspect as a bean. Then we annotate that bean with the @Aspect annotation.

We annotate logBeforeTransfer() of LoggingAspect with the @Before annotation so that this method is called before the transferAmount() is executed. This is called before advice. Then, we annotate another method of LoggingAspect with the @After annotation to declare that the logAfterTransfer() method should be called after transferAmount() has executed. This is known as after advice.

@EnableAspectJAutoProxy is used to enable Spring AOP features in the application. This annotation actually forces you to apply proxy to some of the components that are defined in the spring configuration file. We'll talk more about Spring AOP later, in Chapter 6, Spring Aspect Oriented Programming with Proxy and Decorator Pattern. For now, it's enough to know that you've asked Spring to call logBeforeTransfer() and logAferTransfer() of LoggingAspect before and after the transferAmount() method of the TransferService class. For now, there are two important points to take away from this example:

  • LoggingAspect is still a POJO (if you ignore the @Aspect annotation or are using XML-based configuration)--nothing about it indicates that it's to be used as an aspect.
  • It is important to remember that LoggingAspect can be applied to TransferService without TransferService needing to explicitly call it. In fact, TransferService remains completely unaware of the existence of LoggingAspect.

Let's move to another way that Spring simplifies Java development.

Applying the template pattern to eliminate boilerplate code

At one point in the enterprise application, we saw some code that looked like code we had already written before in the same application. That is actually boilerplate code. It is code that we often have to write again and again in the same application to accomplish common requirements in different parts of the application. Unfortunately, there are a lot of places where Java APIs involve a bunch of boilerplate code. A common example of boilerplate code can be seen when working with JDBC to query data from a database. If you've ever worked with JDBC, you've probably written something in code that deals with the following:

  • Retrieving a connection from the connection pool
  • Creating a PreparedStatement object
  • Binding SQL parameters
  • Executing the PreparedStatement object
  • Retrieving data from the ResultSet object and populating data container objects
  • Releasing all database resources

Let's look at the following code, it contains boilerplate code with the JDBC API of the Java:

    public Account getAccountById(long id) { 
      Connection conn = null; 
      PreparedStatement stmt = null; 
      ResultSet rs = null; 
      try { 
        conn = dataSource.getConnection(); 
        stmt = conn.prepareStatement( 
          "select id, name, amount from " + 
          "account where id=?"); 
        stmt.setLong(1, id); 
        rs = stmt.executeQuery(); 
        Account account = null; 
        if (rs.next()) { 
          account = new Account(); 
          account.setId(rs.getLong("id")); 
          account.setName(rs.getString("name")); 
          account.setAmount(rs.getString("amount")); 
        } 
        return account; 
      } catch (SQLException e) { 
      } finally { 
          if(rs != null) { 
            try { 
              rs.close(); 
            } catch(SQLException e) {} 
          } 
          if(stmt != null) { 
            try { 
              stmt.close(); 
            } catch(SQLException e) {} 
          } 
          if(conn != null) { 
            try { 
              conn.close(); 
            } catch(SQLException e) {} 
          } 
        } 
      return null; 
    } 

In the preceding code, we can see that the JDBC code queries the database for an account name and amount. For this simple task, we have to create a connection, then create a statement, and finally query for the results. We also have to catch SQLException, a checked exception, even though there's not a lot you can do if it's thrown. Lastly, we have to clean up the mess, closing down the connection statement and result set. This could also force it to handle JDBC's exception, so you must catch SQLException here as well. This kind of boilerplate code seriously hurts reusability.

Spring JDBC solves the problem of boilerplate code by using the Template Design pattern, and it makes life very easy by removing the common code in templates. This makes the data access code very clean and prevents nagging problems, such as connection leaks, because the Spring Framework ensures that all database resources are released properly.

The Template Design pattern in Spring

Let's see how to go about using the Template Design pattern in spring:

  • Define the outline or skeleton of an algorithm
  1. Leave the details for specific implementations until later.
  2. Hide away large amounts of boilerplate code.
  • Spring provides many template classes:
  • JdbcTemplate
  • JmsTemplate
  • RestTemplate
  • WebServiceTemplate
  • Most hide low-level resource management

Let's look at the same code that we used earlier with Spring's JdbcTemplate and how it removes the boilerplate code.

Use JdbcTemplates to let your code the focus on the task:

    public Account getAccountById(long id) { 
      return jdbcTemplate.queryForObject( 
        "select id, name, amoount" + 
        "from account where id=?", 
         new RowMapper<Account>() { 
           public Account mapRow(ResultSet rs, 
            int rowNum) throws SQLException { 
              account = new Account(); 
              account.setId(rs.getLong("id")); 
              account.setName(rs.getString("name")); 
              account.setAmount(rs.getString("amount")); 
              return account; 
            } 
         }, 
      id); 
    } 

As you can see in the preceding code, this new version of getAccountById() is much simpler as compared to the boiler plate code, and here the method is focused on selecting an account from the database rather than creating a database connection, creating a statement, executing the query, handling the SQL exception, and finally closing the connection as well. With the template, you have to provide the SQL query and a RowMapper used for mapping the resulting set data to the domain object in the template's queryForObject() method. The template is responsible for doing everything for this operation, such as database connection and so on. It also hides a lot of boilerplate code behind the framework.

We have seen in this section how Spring attacks the complexities of Java development with the power of POJO-oriented development and patterns such as the DI pattern, the Aspect-using Proxy pattern, and the Template method design pattern.

In the next section, we will look at how to use a Spring container to create and manage the Spring beans in the application.

 

Using a Spring container to manage beans with the Factory pattern


Spring provides us with a container, and our application objects live in this Spring container. As shown in the following diagram, this container is responsible for creating and managing the objects:

In a Spring application, our application objects live in this Spring container

The Spring Container also wires the many Object together according to its configuration. It is configured with some initialized parameters, and manages their complete life cycle from start to finish.

Basically, there are two distinct types of Spring container:

  • Bean factory
  • Application contexts

Bean factory

In the Spring Framework, the org.springframework.beans.factory.BeanFactory interface provides the bean factory, which is a Spring IoC container. XmlBeanFactory is an implementation class for this interface. This container reads the configuration metadata from an XML file. It is based on the GOF factory method design pattern--it creates, manages, caches, and wires the application objects in a sophisticated manner. The bean factory is merely an object pool where objects are created and managed by configuration. For small applications, this is sufficient, but enterprise applications demand more, so spring provides another version of the spring container with more features.

In the next section, we will learn about the application context and how Spring creates it in the application.

Application contexts

In the Spring Framework, the org.springframework.context.ApplicationContext interface also provides Spring's IoC container. It is simply a wrapper of the bean factory, providing some extra application context services, such as support for AOP and, hence, declarative transaction, security, and instrumentation support such as support for message resources required for internationalization, and the ability to publish application events to interested event listeners.

Creating a container with an application context

Spring provides several flavors of application context as a bean container. There are multiple core implementations of the ApplicationContext interface, as shown here:

  • FileSystemXmlApplicationContext: This class is an implementation of ApplicationContext that loads application context bean definitions from the configuration files (XML) located in the file system.
  • ClassPathXmlApplicationContext: This class is an implementation of ApplicationContext that loads application context bean definitions from the configuration files (XML) located in the classpath of the application.
  • AnnotationConfigApplicationContext: This class is an implementation of ApplicationContext that loads application context bean definitions from the configuration classes (Java based) from the class path of the application.

Spring provides you with a web-aware implementation of the ApplicationContext interface, as shown here:

  • XmlWebApplicationContext: This class is a web-aware implementation of ApplicationContext that loads application context bean definitions from the configuration files (XML) contained in a web application.
  • AnnotationConfigWebApplicationContext: This class is a web-aware implementation of ApplicationContext that loads Spring web application context bean definitions from one or more Java-based configuration classes.

We can use either one of these implementations to load beans into a bean factory. It depends upon our application configuration file locations. For example, if you want to load your configuration file spring.xml from the file system in a specific location, Spring provides you with a FileSystemXmlApplicationContext, class that looks for the configuration file spring.xml in a specific location within the file system:

    ApplicationContext context = new
     FileSystemXmlApplicationContext("d:/spring.xml"); 

In the same way, you can also load your application configuration file spring.xml from the classpath of your application by using a ClassPathXmlApplicationContext class provided by Spring. It looks for the configuration file spring.xml anywhere in the classpath (including JAR files):

    ApplicationContext context = new 
     ClassPathXmlApplicationContext("spring.xml"); 

If you are using a Java configuration instead of an XML configuration, you can use AnnotationConfigApplicationContext:

    ApplicationContext context = new 
     AnnotationConfigApplicationContext(AppConfig.class); 

After loading the configuration files and getting an application context, we can fetch beans from the Spring container by calling the getBean() method of the application context:

    TransferService transferService = 
     context.getBean(TransferService.class); 

In the following section, we will learn about the Spring bean life cycle, and how a Spring container reacts to the Spring bean to create and manage it.

 

Life of a bean in the container


The Spring application context uses the Factory method design pattern to create Spring beans in the container in the correct order according to the given configuration. So the Spring container has the responsibility of managing the life cycle of the bean from creation to destruction. In the normal java application, Java's new keyword is used to instantiate the bean, and it's ready to use. Once the bean is no longer in use, it's eligible for garbage collection. But in the Spring container, the life cycle of the bean is more elaborate. The following image shows the life cycle of a typical Spring bean:

The life cycle of a Spring bean in the Spring container is as follows:

  1. Load all bean definitions, creating an ordered graph.
  2. Instantiate and run BeanFactoryPostProcessors (you can update bean definitions here).
  3. Instantiate each bean.
  1. Spring injects the values and bean references into the beans' properties.
  2. Spring passes the ID of the bean to the setBeanName() method of the BeanNameAware interface if any bean implements it.
  3. Spring passes the reference of the bean factory itself to the setBeanFactory() method of BeanFactoryAware if any bean implements it.
  4. Spring passes the reference of the application context itself to the setApplicationContext() method of ApplicationContextAware if any bean implements it.
  5. BeanPostProcessor is an interface, and Spring allows you to implement it with your bean, and modifies the instance of the bean before the initializer is invoked in the Spring bean container by calling its postProcessBeforeInitialization().
  6. If your bean implements the InitializingBean interface, Spring calls its afterPropertiesSet() method to initialize any process or loading resource for your application. It's dependent on your specified initialization method. There are other methods to achieve this step, for example, you can use the init-method of the <bean> tag, the initMethod attribute of the @Bean annotation, and JSR 250's @PostConstruct annotation.
  7. BeanPostProcessor is an interface, and spring allows you to implement it with your bean. It modifies the instance of the bean after the initializer is invoked in the spring bean container by calling its postProcessAfterInitialization().
  8. Now your bean is ready to use in the step, and your application can access this bean by using the getBean() method of the application context. Your beans remain live in the application context until it is closed by calling the close() method of the application context.
  9. If your bean implements the DisposibleBean interface, Spring calls its destroy() method to destroy any process or clean up the resources of your application. There are other methods to achieve this step-for example, you can use the destroy-method of the <bean> tag, the destroyMethod attribute of the @Bean annotation, and JSR 250's @PreDestroy annotation.
  10. These steps show the life cycle of Spring beans in the container.
  11. The next section describes the modules that are provided by the Spring Framework.
 

Spring modules


Spring Framework has several distinct modules for a specific set of functionalities, and they work more or less independently of the others. This system is very flexible, so the developer can choose only those required for the enterprise application. For example, a developer can just use the Spring DI module and build the rest of the application with non-Spring components. So, Spring provides integration points to work with other frameworks and APIs--for example, you can use the Spring Core DI pattern only with the Struts application. In case the development team is more proficient in using Struts, it can be used instead of Spring MVC while the rest of the application uses Spring components and features, such as JDBC and transactions. So while the developers need to deploy the required dependencies with the Struts application, there is no need to add a whole Spring Framework.

Here is an overview of the entire module structure:

The various modules of the Spring Framework

Let's look at each of Spring's modules and see how each fits in to the bigger picture.

Core Spring container

This module of the Spring Framework uses lot of the design pattern such as the Factory method design pattern, DI pattern, Abstract Factory Design pattern, Singleton Design pattern, Prototype Design pattern, and so on. All other Spring modules are dependent on this module. You'll implicitly use these classes when you configure your application. It is also called the IoC container and is central to Spring's support for dependency injection, which manages how the beans in a Spring application are created, configured, and managed. You can create Spring container either by using the implementations of BeanFactory or the implementations of the ApplicationContext. This module contains the Spring bean factory, which is the portion of Spring that provides the DI.

Spring's AOP module

Spring AOP is a Java-based AOP Framework with AspectJ integration. It uses dynamic proxies for aspect weaving and focuses on using AOP to solve enterprise problems. This module is based on Proxy and Decorator Design patterns. This module enables the modularization of cross-cutting concerns to avoid tangling and eliminate scattering. Like DI, it supports loose coupling between the core business service and cross-cutting concerns. You can implement your custom aspects and configure them declaratively in your application without impacting on the code of business objects. It provides much flexibility in the code; you could remove or change the aspect logic without touching the code of the business objects. This is a very important module of the spring framework, so I will discuss it in detail in Chapter 6, Spring Aspect Oriented Programming with Proxy and Decorator Pattern of this book.

Spring DAO - data access and integration

Spring DAO and Spring JDBC make life very easy by using templates to remove the common code. The templates implement the GOF template method design pattern and provide suitable extension points to plug in custom code. If you are working with a traditional JDBC application, you have to write lots of boilerplate code to, for example, create a database connection, create a statement, find a result set, handle SQLException, and finally close the connection. If you are working with a Spring JDBC Framework with a DAO layer, then you do not have to write boilerplate code, unlike a traditional JDBC application. That means that Spring allows you to keep your application code clean and simple.

Spring's ORM

Spring also provides support to ORM solutions, and it provides integration with ORM tools for easy persistence of POJO objects in relational databases. This module actually provides an extension to the Spring DAO module. Like JDBC-based templates, Spring provides ORM templates to work with leading ORM products, such as Hibernate, JPA, OpenJPA, TopLink, iBATIS, and so on.

Spring web MVC

Spring provides a web and remote module for the enterprise web application. This module helps build highly flexible web applications, leveraging the complete benefits of the Spring IOC container. This module of Spring uses the patterns such as the MVC architectural pattern, Front Controller pattern, and the DispatcherServlet Pattern, and it seamlessly integrates with the servlet API. The Spring web module is very pluggable and flexible. We can add any of the view technologies, such as JSP, FreeMarker, Velocity, and so on. We can also integrate it with other frameworks, such as Struts, Webwork, and JSF, using spring IOC and DI.

 

New features in Spring Framework 5.0


Spring 5.0 is the freshest release of Spring available. There are a lot of exciting new features in Spring 5.0, including the following:

  • Support for JDK 8 + 9 and Java EE 7 Baseline:

Spring 5 supports Java 8 as a minimum requirement, as the entire framework codebase is based on Java 8.

Spring Framework required at least Java EE 7 to run Spring Framework 5.0 applications. That means it requires Servlet 3.1, JMS 2.0, JPA 2.1.

  • Deprecated and removed packages, classes, and methods:

In Spring 5.0, some packages have been either removed or deprecated. It has had a package called mock.static removed from the spring-aspects module, and hence there is no support for AnnotationDrivenStaticEntityMockingControl.

Packages such as web.view.tiles2 and orm.hibernate3/hibernate4 have also been removed as of Spring 5.0. Now, in the latest spring framework, Tiles 3 and Hibernate 5 are being used.

The Spring 5.0 framework doesn't support Portlet, Velocity, JasperReports, XMLBeans, JDO, Guava (and so on) anymore.

Some deprecated classes and methods of earlier versions of Spring have been removed as of Spring 5.0.

  • Adding the new reactive programming model:

This model of programming has been introduced in the Spring 5.0 Framework. Let's look at the following listed point about the reactive programming model.

Spring 5 introduced the Spring-core module DataBuffer and encoder/decoder abstractions with non-blocking semantics into the reactive programming model.

Using the reactive model, Spring 5.0 provides the Spring-web module for HTTP message codec implementations with JSON (Jackson) and XML (JAXB) support.

The Spring reactive programming model added a new spring-web-reactive module with reactive support for the @Controller programming model, adapting reactive streams to Servlet 3.1 containers, as well as non-Servlet runtimes, such as Netty and Undertow.

Spring 5.0 also introduced a new WebClient with reactive support on the client side to access services.

As listed here, you can see that there are a lot of exciting new features and enhancements in the Spring Framework 5. So in this book, we will look at many of these new features with examples and their adopted design patterns.

 

Summary


After reading this chapter, you should now have a good overview of the Spring Framework and its most-used design patterns. I highlighted the problem with the J2EE traditional application, and how Spring solves these problems and simplifies Java development by using lots of design patterns and good practices to create an application. Spring aims to make enterprise Java development easier and to promote loosely coupled code. We have also discussed Spring AOP for cross-cutting concerns and the DI pattern for use with loose coupling and pluggable Spring components so that the objects don't need to know where their dependencies come from or how they're implemented. Spring Framework is an enabler for best practices and effective object design. Spring Framework has two important features--First it has a Spring container to create and manage the life of beans and second it provides support to several modules and integration to help simplify Java development.

About the Author

  • Dinesh Rajput

    Dinesh Rajput is a founder of Dineshonjava (dot) com, a blog for Spring and Java techies. He is a Spring enthusiast and a Pivotal Certified Spring Professional. He has written two bestselling books, Spring 5 Design Patterns and Mastering Spring Boot 2.0. Mastering Spring Boot 2.0 is the Amazon #1 best-selling book on Java. He has more than 10 years of experience with various aspects of Spring and cloud-native development, such as REST APIs and microservice architecture. He is currently working as an architect at a leading company. He has worked as a tech lead at Bennett, Coleman & Co. Ltd, and Paytm. He has a master's degree in computer engineering from JSS Academy of Technical Education, Noida, and lives in Noida with his family.

    Browse publications by this author

Latest Reviews

(2 reviews total)
A very interesting book taht will teach you a lot both about Spring and software design patterns
A very good written book with informative contents, that can we use in our projects as per requirement, its always be a good journey under mentoring of Dinesh Sir,

Recommended For You

Book Title
Unlock this full book FREE 10 day trial
Start Free Trial