Tel application is a Rest based Application that provides functionality for adding, updating, and deleting a customer.
we will build this application incrementally to make it for learning the Spring core concepts with Spring Boot.
Tel is built as a three-tier application which consists of
The service layer of an enterprise application is the layer in which the business logic is implemented. It interacts with the persistence layer and the presentation layer.
Spring Core with Boot, we will see how to develop the Service/Business layer for this application. Once you have completed this course you can then learn to build the Persistence layer using Spring JDBC with Spring Boot course and, to build the Rest presentation layer using Spring REST course.
Below are the classes used in the Tel application.
In this implementation, CustomeServiceImpl depends on CustomerRepository. It also instantiates CustomerRepositoryImpl class which makes it tightly coupled with CustomerRepositoryImpl class. This is a bad design because of the following reasons:
So we need a more flexible solution where dependencies can be provided externally rather than a dependent creating its own dependencies
In this implementation, CustomerServiceImpl doesn’t create an object of the CustomerRepository. Instead, it is giving an object of CustomerRepository at creation time as a constructor argument. You can pass the object of any class that implements CustomerRepository interface at the time of object creation of CustomerServiceImpl class as a constructor argument. This makes CustomerServiceImpl class loosely coupled with CustomerRepositoryImpl class. So you can now easily test CustomerServiceImpl class by substituting its CustomerRepositoryImpl object with a mock CustomerRepository. Also, you can use any implementations of CustomerRepository inside CustomerServiceImpl.
This solution is more flexible and easy to test. But at the same time, it is tedious to manually wire together with the dependencies. Also if you alter the dependencies you may have to change vast amounts of code. So what is the solution?
We can use a technique called Dependency Injection (DI). It is a technique in which the responsibility of creating and wiring the dependencies of a dependent class is externalized to the external framework or library called dependency injection (DI) frameworks. So now the control over the construction and wiring of an object graph is no longer resides with the dependent classes themselves. This reversal of responsibilities is known as Inversion of Control(IoC). Dependency injection framework also called IoC containers.
There are many third-party frameworks that are available for dependency injection such as Spring Framework, Google Guice, Play Framework, etc. In this course, you will study about Spring Framework. Besides dependency injection, there are many other advantages of using the Spring Framework which you will study later in this course.
Note: Inversion of Control (IoC) represents the inversion of application responsibility of the object's creation, initialization, dependency, and destruction from the application to the third party.
Spring Framework is an open source Java application development framework that supports developing all types of Java applications such as enterprise applications, web applications, cloud based applications, and many more.
Java applications developed using Spring are simple, easily testable, reusable, and maintainable.
Spring modules do not have tight coupling on each other, the developer can pick and choose the modules as per the need for building an enterprise application.
Spring Feature | Description |
---|---|
Light Weight | Spring JARs are relatively small. A basic Spring framework would be lesser than 10MB. It can be deployed in Tomcat and they do not require heavy-weight application servers. |
Non-Invasive | The application is developed using POJOs. No need to extend/implement any pre-defined classes. |
Loosely Coupled | Spring features like Dependency Injection and Aspect Oriented Programming help in loosely coupled code. |
Inversion of Control(IoC) | IoC takes care of the application object's life cycle along with their dependencies. |
Spring Container | Spring Container takes care of object creation, initialization, and managing object dependencies. |
Aspect Oriented Programming(AOP) | Promotes separation of supporting functions(concerns) such as logging, transaction, and security from the core business logic of the application |
Spring Framework 5.x has the following key module groups:
Core container has the following modules:
The following modules support Data Access/Integration:
Spring Framework provides the following modules to support web application development:
Usually it is the developer's responsibility to create the dependent application object using the new operator in an application. Hence any change in the application dependency requires code change and this results in more complexity as the application grows bigger.
Inversion of Control (IoC) helps in creating a more loosely coupled application. IoC represents the inversion of the responsibility of the application object's creation, initialization, and destruction from the application to the third party such as the framework. Now the third party takes care of application object management and dependencies thereby making an application easy to maintain, test, and reuse.
There are many approaches to implement IoC, Spring Framework provides IoC implementation using Dependency Injection(DI).
Spring Container managed application objects are called beans in Spring.
We need not create objects in dependency injection instead describe how objects should be created through configuration.
DI is a software design pattern that provides better software design to facilitate loose coupling, reuse, and ease of testing.
Benefits of Dependency Injection(DI):
BeanFactory:
ApplicationContext is the preferred container for Spring application development. Let us look at more details on the ApplicationContext container.
AbstractApplicationContext
AbstractApplicationContext
Spring allows providing the configuration metadata using :
The Java-based configuration metadata is provided in the Java class using the following annotations:
@Configuration: The Java configuration class is marked with this annotation. This annotation identifies this as a configuration class, and it’s expected to contain details on beans that are to be created in the Spring application context.
@Bean: This annotation is used to declare a bean. The methods of configuration class that creates an instance of the desired bean are annotated with this annotation. These methods are called by the Spring containers during bootstrap and the values returned by these methods are treated as Spring beans. By default, only one bean instance is created for a bean definition by the Spring Container, and that instance is used by the container for the whole application lifetime.
Highlights:
How do we initialize beans with some specific values in Spring?
This can be achieved through Dependency Injection in Spring.
Inversion of Control pattern is achieved through Dependency Injection (DI) in Spring. In Dependency Injection, the developer need not create the objects but specify how they should be created through configuration.
Spring container uses one of these two ways to initialize the properties:
What is mandatory for constructor injection?
A parameterized constructor is required in the CustomerService class as we are injecting the values through the constructor argument.
Can we use constructor injection to initialize multiple properties?
Yes, we can initialize more than one property.
Observe in the above code, CustomerRepository property of CustomerSevice class has not been initialized with any value in the code. This is because Spring dependency is going to be taken care of in the configuration.
How do we inject object dependencies through configuration using constructor injection?
In Setter Injection, Spring invokes setter methods of a class to initialize the properties after invoking a default constructor.
How can we use setter injection to inject values for the primitive type of properties
What is mandatory to implement setter injection?
Default constructor and setter methods of respective dependent properties are required in the CustomerServiceImpl class. For setter injection, Spring internally uses the default constructor to create a bean and then invokes a setter method of the respective property based on the name attribute in order to initialize the values.inject primitive values using setter injection in Spring.
How do we inject object dependencies using setter injection?
Is any other way to eliminate this tedious beans declaration?
Yes, Spring provides a way to automatically detect the beans to be injected and avoid even the bean definitions within the Spring configuration file through Auto Scanning. In Auto Scanning, Spring Framework automatically scans, detects, and instantiates the beans from the specified base package, if there is no declaration for the beans in the SpringConfiguration class.
what are Stereotype annotations?
Annotation | Usage |
---|---|
@Component | It indicates the class(POJO class) as a Spring component. |
@Service | It indicates the Service class(POJO class) in the business layer. |
@Repository | It indicates the Repository class(POJO class in Spring DATA) in the persistence layer. |
@Controller | It indicates the Controller class(POJO class in Spring MVC) in the presentation layer. |
Configuring IOC container java Annotation based configuration
have learned that Spring is a lightweight framework for developing enterprise Java applications. But using Spring for application development is challenging for developer because of the following reason which reduces productivity and increases the development time:
1. Configuration
You have seen that the Spring application requires a lot of configuration. This configuration also needs to be overridden for different environments like production, development, testing, etc. For example, the database used by the testing team may be different from the one used by the development team. So we have to spend a lot of time writing configuration instead of writing application logic for solving business problems.
2. Project Dependency Management
When you develop a Spring application you have to search for all compatible dependencies for the Spring version that you are using and then manually configure them. If the wrong version of dependencies is selected then it will be an uphill task to solve this problem. Also for every new feature added to the application, the appropriate dependency needs to be identified and added. All this reduces productivity.
So to handle all these kinds of challenges Spring Boot came into the market.
What is Spring Boot?
Spring Boot is a framework built on top of the Spring framework that helps the developers to build Spring-based applications very quickly and easily. The main goal of Spring Boot is to create Spring-based applications quickly without demanding developers to write the boilerplate configuration.
But how does it work? It works because of the following reasons,
1. Spring Boot is an opinionated framework
Spring Boot forms . It means that Spring Boot has some sensible defaults which you can use to quickly build your application. For example, Spring Boot uses embedded Tomcat as the default web container.
2. Spring Boot is customizable
Though Spring Boot has its defaults, you can easily customize it at any time during your development based on your needs. For example, if you prefer log4j for logging over Spring Boot built-in logging support then you can easily make a dependency change in your pom.xml file to replace the default logger with log4j dependencies.
The main Spring Boot features are as follows:
There are multiple approaches to create a Spring Boot application. You can use any of the following approaches to create the application:
It is an online tool provided by Spring for generating Spring Boot applications which is accessible at http://start.spring.io/. You can use it for creating a Spring Boot project using the following steps:
Step 1: Create your Spring Boot application launch Spring Initializr. You will get the following screen:
Step 2: Select Project as Maven, Language as Java, and Spring Boot as 2.1.13 and enter the project details as follows:
Click on More options and choose com.infy as Package Name
Step 3: Click on Generate Project. This would download a zip file to your local machine.
Step 4: Unzip the zip file and extract it to a folder.
Step 5: In Eclipse, Click File → Import → Existing Maven Project. Navigate or type in the path of the folder where you extracted the zip file to the next screen. click finishing,
2. application.properties
This file contains application-wide properties. To configure your application Spring reads the properties defined in this file. In this file, you can define a server’s default port, the server’s context path, database URLs, etc.
3. DemoSpringBootApplication.java
It is annotated with @SpringBootApplication annotation which triggers auto-configuration and component scanning and can be used to declare one or more @Bean methods also. It contains the main method which bootstraps the application by calling the run() method on the SpringApplication class. The run method accepts DemoSpringBootApplication.class as a parameter to tell Spring Boot that this is the primary component.
4. DemoSpringBootApplicationTest.java
In this file test cases are written. This class is by default generated by Spring Boot to bootstrap Spring application.
Spring Boot starters are pre-configured dependency descriptors with the most commonly used libraries that you can add to your application. So you don't need to search for compatible libraries and configure them manually. Spring Boot will ensure that the necessary libraries are added to the build. To use these starters, you have to add them to the pom.xml file. For example, to use spring-boot-starter following dependency needs to be added in pom.xml:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
Spring Boot comes with many starters. Some popular starters which we are going to use in this course are as follows:
Spring Boot Starter Parent
The Spring Boot Starter Parent defines key versions of dependencies and default plugins for quickly building Spring Boot applications. It is present in the pom.xml file of the application as a parent
Executing the Spring Boot application
To execute the Spring Boot application run the DemoSpringBootApplication as a standalone Java class which contains the main method.
Spring Boot Runners
So far you have learned how to create and start the Spring Boot application. Now suppose you want to perform some action immediately after the application has started then for this Spring Boot provides the following two interfaces:
CommandLineRunner is the Spring Boot interface with a run() method. Spring Boot automatically calls this method of all beans implementing this interface after the application context has been loaded. To use this interface, you can modify the DemoSpringBootApplication class as follows:
In this file, various default properties are specified to support logging, AOP, JPA, etc. All the default properties need not be specified in all cases. We can specify them only on-demand. At startup, the Spring application loads all the properties and adds them to the Spring Environment class.
To use a custom property add it to the application.properties file.
You can use other files to keep the properties. For example, InfyTelmessage.properties.
InfyTelmessage.properties
But by default Spring Boot will load only the application.properties file. So how you will load the InfyTelmessage.properties file?
In Spring @PropertySource annotation is used to read from properties file using Spring’s Environment interface. The location of the properties file is mentioned in the Spring configuration file using @PropertySource annotation.
So InfyTelmessage.properties which are present in classpath can be loaded using @PropertySource
import org.springframework.context.annotation.PropertySource;
@SpringBootApplicationThe @SpringBootApplication annotation indicates that it is a configuration class and also triggers auto-configuration and component scanning. It is a combination of the following annotations with their default attributes:
@EnableAutoConfiguration – This annotation enables auto-configuration for the Spring boot application which automatically configures our application based on the dependencies that you have added.
@ComponentScan – This enables the Spring bean dependency injection feature by using @Autowired annotation. All application components which are annotated with @Component, @Service, @Repository, or @Controller are automatically registered as Spring Beans. These beans can be injected by using @Autowired annotation.
@Configuration – This enables Java based configurations for Spring boot application.
The class that is annotated with @SpringBootApplication will be considered as the main class, is also a bootstrap class. It kicks starts the application by invoking the SpringApplication.run() method. You need to pass the .class file name of your main class to the run() method.
SpringBootApplication- scanBasePackages
By default, SpringApplication scans the configuration class package and all it’s sub-packages. So if our SpringBootApplication class is in "com.eta" package, then it won’t scan com.infy.service or com.infy.repository package. We can fix this situation using the SpringBootApplication scanBasePackages property.
In Spring if one bean class is dependent on another bean class then the bean dependencies need to be explicitly defined in your configuration class. But you can let the Spring IoC container to inject the dependencies into dependent bean classes without been defined in your configuration class. This is called as autowiring.
To do autowiring, you can use @Autowired annotation. This annotation allows the Spring IoC container to resolve and inject dependencies into your bean.@Autowired annotation performs byType Autowiring i.e. dependency is injected based on bean type. It can be applied to attributes, constructors, setter methods of a bean class.
Autowiring is done only for dependencies to other beans. It doesn't work for properties such as primitive data types, String, Enum, etc. For such properties, you can use the @Value annotation.
@Autowired on Setter methods
The @Autowired annotation can be used on setter methods. This is called a Setter Injection.
@Autowired on Constructor
The @Autowired annotation can also be used on the constructor. This is called a Constructor Injection.
@Autowired on Properties
Let us now understand the usage of @Autowired on a property in Spring.
We will use @Autowired in the below code to wire the dependency of CustomerService class for CustomerRepository bean dependency.
@Autowired is by default wire the dependency based on the type of bean.
In the above code, the Spring container will perform dependency injection using the Java Reflection API. It will search for the class which implements CustomerRepository and injects its object. The dependencies which are injected using @Autowired should be available to the Spring container when the dependent bean object is created. If the container does not find a bean for autowiring, it will throw the NoSuchBeanDefinitionException exception.
If more than one beans of the same type are available in the container, then the framework throws an exception indicating that more than one bean is available for autowiring. To handle this @Qualifier annotation is used as follows:
@Value annotation:
In Spring @Value annotation is used to insert values into variables and method arguments. Using @Value we can either read spring environment variables or system variables.
We can assign a default value to a class property with @Value annotation:
Note that it accepts only a String argument but the passed-in value gets converted to an appropriate type during value-injection.
To read a Spring environment variable we can use @Value annotation:
public class CustomerDTO {
@Value("${value.phone}")
long phoneNo;
@Value("${value.name}")
String name;
@Value("${value.email}")
String email;
@Value("${value.address}")
String address;
}
The lifetime of a bean depends on its scope. Bean's scope can be defined while declaring it in the configuration metadata file.
A bean can be in singleton or prototype scope. A bean with the "singleton" scope is initialized during the container starts up and the same bean instance is provided for every bean request from the application. However, in the case of the "prototype" scope, a new bean instance is created for every bean request from the application.
There will be a single instance of "singleton" scope bean in the container and the same bean is given for every request from the application.
The bean scope can be defined for a bean using @Scope annotation in Java class. By default, the scope of a bean is the singleton
For the "prototype" bean, there will be a new bean created for every request from the application.
In the below example, customerService bean is defined with prototype scope. There will be a new customerService bean created for every bean request from the application.
What is logging?
Logging is the process of writing log messages to a central location during the execution of the program. That means Logging is the process of tracking the execution of a program, where
There are several logging APIs to make logging easier. Some of the popular ones are:
The Logger is the object which performs the logging in applications.
Levels in the logger specify the severity of an event to be logged. The logging level is decided based on necessity. For example, TRACE can be used during development and ERROR during deployment.
By default, Spring Boot configures logging via Logback to log the activities of libraries that your application uses.
As a developer, you may want to log the information that helps in quick problem diagnosis, debugging, and maintenance. So, let us see how to customize the default logging configuration of Spring Boot so that your application can log the information that you are interested in and in your own format.
Log error message :
Have you realized that you have not done any of the below activities for logging which you typically do in any Spring application?
Adding dependent jars for loggingStill, you are able to log your messages. The reason is Spring Boot's default support for logging. The spring-boot-starter dependency includes spring-boot-starter-logging dependency, which configures logging via Logback to log to the console at the INFO level.
Spring Boot uses Commons Logging API with default configurations for Java Util Logging, Log4j 2, and Logback implementation. Among these implementations, Logback configuration will be enabled by default.
You, as a developer, have just created an object for Logger and raise a request to log with your own message in LoggingAspect.java as shown below.
how to change this default configuration if you want to,
Log into file
By default Spring Boot logs the message on the console. To log into a file, you have to include either logging.file or logging. path property in your application.properties file.
Note: Please note that from Spring boot 2.3.X version onwards logging.file and logging.path has been deprecated we should use "logging.file.name" and " logging.file.path" for the same.
Custom log pattern
Include logging.pattern.* property in application.properties file to write the log message in your own format.
Logging property | Sample value | Description |
---|---|---|
logging.pattern.console | %d{yyyy-MM-dd HH:mm:ss,SSS} | Specifies the log pattern to use on the console |
logging.pattern.file | %5p [%t] %c [%M] - %m%n | Specifies the log pattern to use in a file |
Custom log level
By default, the logger is configured at the INFO level. You can change this by configuring the logging.level.* property in application.properties file as shown below.
Log4j instead of Logback
Since Spring Boot chooses Logback implementation by default, you need to exclude it and then include log4j 2 instead of in your pom.xml.
AOP is used for applying common behaviors like transactions, security, logging, etc. to the application.
These common behaviors generally need to be called from multiple locations in an application. Hence, they are also called as cross cutting concerns in AOP.
Spring AOP provides the solution to cross cutting concerns in a modularized and loosely coupled way.
Advantages
AOP ensures that cross cutting concerns are kept separate from the core business logic.
Based on the configurations provided, the Spring applies cross cutting concerns appropriately during the program execution.
This allows creating a more loosely coupled application wherein you can change the cross cutting concerns code without affecting the business code.
In Object Oriented Programming(OOP), the key unit of modularity is class. But in AOP the key unit of modularity is an Aspect.
What is an Aspect?
Aspects are the cross-cutting concerns that cut across multiple classes.
Examples: Transaction Management, Logging, Security, etc.
Type Of Execution | Execution Point |
---|---|
Before | Before advice is executed before the Joinpoint execution. |
After | After advice will be executed after the execution of Joinpoint whether it returns with or without exception. Similar to finally block in exception handling. |
AfterReturning | AfterReturning advice is executed after a Joinpoint executes and returns successfully without exceptions |
AfterThrowing | AfterThrowing advice is executed only when a Joinpoint exits by throwing an exception |
Around | Around advice is executed around the Joinpoints which means Around advice has some logic which gets executed before Joinpoint invocation and some logic which gets executed after the Joinpoint returns successfully |
A pointcut is an important part of AOP. So let us look at pointcut in detail.
Pointcut expressions have the following syntax:
where,
Pointcut | Description |
---|---|
execution(public * *(..)) | execution of any public methods |
execution(* service *(..)) | execution of any method with a name beginning with "service" |
execution(*com.infy.service.CustomerServiceImpl.*(..)) | execution of any method defined in CustomerServiceImpl of com.infy.service package |
execution(* com.infy.service.*.*(..)) | execution of any method defined in the com.infy.service package |
execution(public * com.infy.service.CustomerServiceImpl.*(..)) | execution of any public method of CustomerServiceImpl of com.infy.service package |
execution(public String com.infy.service.CustomerserviceImpl.*(..)) | execution of all public method of CustomerServiceImpl of com.infy.service package that returns a String |
Before Advice:
This advice is declared using @Before annotation. It is invoked before the actual method call. ie. This advice is executed before the execution of fetchCustomer()methods of classes present in com.infy.service package.
After Advice:
This advice is declared using @After annotation. It is executed after the execution of the actual method(fetchCustomer), even if it throws an exception during execution. It is commonly used for resource cleanup such as temporary files or closing database connections.
After Returning Advice
This advice is declared using @AfterReturning annotation. It gets executed after joinpoint finishes its execution. If the target method throws an exception the advice is not executed. The following is an example of this advice that is executed after the method execution of fetchCustomer()method of classes present in com.infy.service package.
AfterThrowing Advice :
This advice is defined using @AfterThrowing annotation. It gets executed after an exception is thrown from the target method. The following is an example of this advice that gets executed when exceptions are thrown from the fetchCustomer() method of classes present in com.infy.service package
Around advice:
This advice gets executed around the joinpoint i.e. before and after the execution of the target method. It is declared using @Around annotation
The best practices which need to be followed as part of the Quality and Security for the Spring application and Spring with Spring Boot applications. These practices, when applied during designing and developing a Spring/Spring Boot application, yields better performance.
Best Practices:
There are three different ways to create a Spring Boot project. They are:
But the recommended and simplest way to create a Spring Boot application is the Spring Boot Initializr as it has a very good UI to download a production-ready project. And the same project can be directly imported into the STS/Eclipse.
There are two recommended ways to create a spring boot project structure for Spring boot applications, which will help developers to maintain a standard coding structure.
Don't use the “default” Package:
When a developer doesn't include a package declaration for a class, it will be in the “default package”. So the usage of the “default package” should be avoided as it may cause problems for Spring Boot applications that generally use the annotations like @ComponentScan, or @SpringBootApplication. So, during the creation of the classes, the developer should follow Java's package naming conventions. For example, com.infosys.client, com.infosys.service, com.infosys.controller etc.
There are 2 approaches that can be followed to create a standard project structure in Spring boot applications.
First approach: The first approach shows a layout which generally recommended by the Spring Boot team. In this approach we can see that all the related classes for the customer have grouped in the "net.guides.springboot2.cutomer" package and all the related classes for the order have grouped in the "net.guides.springboot2.order" package
Second approach: However the above structure works well but developers prefer to use the following structure.
In this approach, we can see that all the service classes related to customer and Order are grouped in the net.guide.springboot2.service package. Similar to that we can see we grouped the dao, controller, and model classes
Avoid creating beans for the domain class like the above.
java doesn't allow annotations placed on interfaces to be inherited by the implemented class so make sure that we place the spring annotations only on class, fields, or methods.
As a good practice place @Autowired annotation before a constructor.
We know that there are three places we can place @Autowired annotation in Spring on fields, on setter method, and on a constructor. The classes using field injection are difficult to maintain and it is very difficult to test. The classes using setter injection will make testing easy, but this has some disadvantages like it will violate encapsulation. Spring recommends that use @Autowired on constructors that are easiest to test, and the dependencies can be immutable.
If we want to create a stateless bean then singleton scope is the best choice. In case if you need a stateful bean then choose prototype scope.
A Spring application developer can mix the Constructor injection and Setter injection in the same application but it's a good practice to use constructor injection for mandatory dependencies and Setter injection for optional dependencies.
Problem Statement
Background: This problem statement provides the high level design of the project that has to be implemented as part of the hands-on assessment in order to complete the course Spring Basics.
InfyGo is an airline booking application that provides services to its customers to search for flight details. InfyGo wants a lightweight, loosely coupled application to be implemented using Spring.
Let us start with basic implementation using Spring core concepts for the following functionalities
As part of the Spring Basics course, let us develop the business tier of this application.
Implement the application using the following classes:
Domain class Flight with below details
Implement the required repository using the collection
Implement the Service layer of the application
Implement client code to access bean of FlightServiceImpl class and perform below tasks in a menu based approach.
Add Flight: Add flight details by auto generating FlightId starting from 1001 and accepting other flight details from the user
Search Flight: User can Search flights based on source, destination, and journey date
Note: Assume as of now the application is accessible to the user who can perform all the above functionalities.
Implement the Spring Boot application with the following features:
Implement LoggingAspect class for logging details whenever the new flight details are added
List: Link tgs Dropdown