Module 2
Module 2
MODULE 2:
SpringBoot: WhatisSpringBoot-CreatingaProjectwithSpringBootInitializer,
Wirebeans together in the Spring container using Inversion of Control,
Configure the Spring container for Dependency Injection, Define Spring
Beans using the Component annotation, perform auto- scanning of Spring
beans to minimize configuration, Automatically wire beans together using
Auto wired annotation, Apply all Java configuration to Spring Beans (no
xml).
One of the primary uses of Spring Boot is to create web applications. It makes it easy
to build both traditional web apps and RESTful APIs. With Spring Boot, you can
create web applications quickly by leveraging features like:
• Thymeleaf and other template engines for rendering dynamic web pages.(html)
• Embedded Tomcat server, which allows you to run your web application
without needing to configure an external web server.
import [Link];
import [Link];
import [Link];
import [Link];
@SpringBootApplication
publicclassMyWebApp{ publicstaticvoidmain(String[] args) {
[Link]([Link], args);
}
}
@RestController
classHelloController{ @GetMapping("/hello")
public String sayHello()
{ return"Hello, Spring Boot!";
}
}
Spring Boot is widely used to build RESTful web services. REST APIs are a
common way to allow different systems or clients (such as web browsers or mobile
apps) to interact with your backend services. Spring Boot simplifies the process of
creating these APIs with minimal boilerplate code.
Example:
import [Link].*;
@RestController
@RequestMapping("/api")
publicclassApiController
{
CLOUD COMPUTING FULL STACK DEVELOPMENT-MVJ22CS61
@GetMapping("/greeting")
public String getGreeting()
{
return"Hello, this is a REST API!";
}
}
Microservices Development
Spring Boot is one of the top choices for building microservices. A microservice is a
small, independent service that performs a specific function and communicates with
other services to build larger systems. Spring Boot’s lightweight, modular design
makes it easy to create, deploy, and scale microservices.
Spring Boot works seamlessly with Spring Cloud, which adds tools for managing
microservices, such as:
Another common use of Spring Boot is to manage databases and data storage. Spring
Boot supports various databases, including MySQL, PostgreSQL, MongoDB,
and H2. It integrates seamlessly with Spring Data JPA, which simplifies database
access and management by using an Object-Relational Mapping (ORM) approach.
import [Link];
publicinterfaceUserRepositoryextendsJpaRepository<User, Long>
{
User findByUsername(String username);
}
CLOUD COMPUTING FULL STACK DEVELOPMENT-MVJ22CS61
Spring Boot’s modular approach allows developers to add features as needed without
overwhelming the system. This makes it perfect for building both small and large
applications.
Spring Boot is often used to build standalone applications. You can package your
Spring Boot application as a JAR file and run it without needing an external web
server. This is particularly useful for creating small tools, utilities, or background
services.
With the built-in Spring Boot CLI (Command Line Interface), you can even write
and run Spring Boot applications directly from the command line, making it easy to
develop and test quick solutions.
Using tools like Spring Cloud, you can build cloud-ready, scalable, and resilient
applications. Spring Cloud helps manage distributed systems, providing features like
centralized configuration, load balancing, and service discovery.
CLOUD COMPUTING FULL STACK DEVELOPMENT-MVJ22CS61
Rapid Prototyping
Spring Boot is often used for rapid prototyping because of how quickly you can
create and deploy an application. With Spring Boot’s Spring Initializr, you can
generate a project within minutes, add dependencies, and start building your prototype.
This makes it perfect for developers who need to build proof-of-concept applications
quickly.
Auto-Configuration
One of the biggest reasons Spring Boot is called opinionated is its auto-
configuration feature. When you create a Spring Boot project and add certain
dependencies (such as a database or web framework), Spring Boot
automatically configures them for you.
For example:
You don’t need to write configuration files or deal with manual setup—Spring
Boot makes an assumption about what you need and configures it accordingly.
Starter Dependencies
Production-Ready Features
For example:
This makes development faster because you don’t need to spend time
configuring things that have widely accepted standards or defaults. However,
if you need to customize these settings, Spring Boot allows youto override
them.
Presentation layer: This is the user interface of the application that presents the
application’s features and data to the user.
Presentation layer: This is the user interface of the application that presents the
application’s features and data to the user.
Business logic (or Application) layer: This layer contains the business logic that
drives the application’s core functionalities. Like making decisions, calculations,
evaluations, and processing the data passing between the other two layers.
Data access layer (or Data) layer: This layer is responsible for interacting with
databases to save and restore application data.
Let's see how these two architectural patterns (both containing three connected
components) relate to each other.
The MVC pattern is only concerned with organizing the logic in the user interface
(presentation layer).
CLOUD COMPUTING FULL STACK DEVELOPMENT-MVJ22CS61
As the name implies, the MVC pattern has three layers: The Model defines the
business layer of the application, the Controller manages the flow of the application,
and the View defines the presentation layer of the application.
The Model Layer - This is the data layer which contains the business logic of
the system, and also represents the state of the application. It’s independent of
the presentation layer, the controller fetches the data from the Model layer and
sends it to the View layer.
The View Layer - This layer represents the output of the application, usually
some form of UI. The presentation layer is used to display the Model data
fetched by the Controller.
Three-tier architecture has a broader concern. It’s about organizing the code in the
whole application.
The controller component of MVC is the connection point between the two layers:
CLOUD COMPUTING FULL STACK DEVELOPMENT-MVJ22CS61
In a Spring MVC web application, the three layers of the architecture will manifest as
follows:
• Controller classes as the presentation layer. Keep this layer as thin as possible
and limited to the mechanics of the MVC operations, e.g., receiving and
validating the inputs, manipulating the model object, returning the
appropriate ModelAndView object, and so on. All the business-related
operations should be done in the service classes. Controller classes are usually
put in a controller package.
Consider below Spring MVC web application using Spring boot and thymeleaf. We
have created a three-layer architecture and each layer is mapped to the corresponding
package.
For example:
Use the default constructor and reflection to instantiate private class fields.
To handle this automatic wiring, Spring uses the @Autowired annotation, which
marks the points where dependencies should be injected. You can place
@Autowired on constructors, methods, and properties to indicate where Spring
should inject dependencies.
Setter-based DI involves creating an object using the default constructor and then
setting its dependencies through setter methods.
Example:
package [Link];
import [Link];
import [Link];
@Component
CLOUD COMPUTING FULL STACK DEVELOPMENT-MVJ22CS61
public Sandwich() {
// Default constructor
@Autowired
[Link] = bread;
@Autowired
[Link] = cheese;
Example:
package [Link];
import [Link];
import [Link];
@Component
[Link] = lettuce;
[Link] = tomato;
finds all the required dependencies in the application context and uses them in the
Salad constructor to instantiate the object.
Example:
package [Link];
import [Link];
import [Link];
@Component
@Autowired
@Autowired
In this example, @Autowired is placed directly on the fields water and sugar. Spring
uses reflection to inject dependencies into these private fields. While convenient,
CLOUD COMPUTING FULL STACK DEVELOPMENT-MVJ22CS61
this method is generally discouraged due to its reduced testability and encapsulation
issues.
Spring also allows for method-based dependency injection using the @Bean
annotation. This technique involves injecting dependencies via method parameters
in Java configuration classes.
Example:
package [Link];
import [Link];
import [Link];
@Configuration
@Bean
@Bean
}
CLOUD COMPUTING FULL STACK DEVELOPMENT-MVJ22CS61
@Bean
In this example, the sandwich method is annotated with @Bean, and it takes Bread
and Cheese as parameters. Spring's application context will automatically resolve
these dependencies by calling the bread and cheese methods, respectively, to supply
the required beans. This method-based injection is useful for creating bean instances
that depend on other beans defined in the same configuration class.
Bean-stantiation
For this article, we assume an understanding that classes are templates from which
objects are created. The process of creating an instance from a class is known as
instantiation. In terms of reusability, we should also have the understanding that
custom objects can be nested inside of other classes.
CLOUD COMPUTING FULL STACK DEVELOPMENT-MVJ22CS61
Normally, instantiating an object from a class requires the use of the new keyword.
Let’s take a look at how we would normally use nested objects and compare it to a
similar process when using Spring beans.
Imagine we are designing a racing game. For each round of the race we need a race
track and drivers. We could create a class for both as shown below.
publicclassRaceTrack{
privateString location;
privateint miles;
privateString trackType;
}
publicclassDriver{
privateString name;
privateString team;
privateint yearsExperience;
}
Now let’s create a class that can be used for each round of the race.
publicclassRaceRound{
privateStringstartTime;
privateRaceTrack=newRaceTrack();
privateDriver=newDriver();
}
For each round of the race we would need to instantiate a RaceTrack and a Driver, so
we would use the new keyword to handle those instantiations. Any changes to those
two classes would require additional changes in the RaceRound class.
Now let’s take a look at how instantiating the nested objects would work with Spring
beans. We would first mark our RaceTrack and Driver classes as Spring beans using
the @Component annotation:
CLOUD COMPUTING FULL STACK DEVELOPMENT-MVJ22CS61
@Component
publicclassRaceTrack{
privateString location;
privateint miles;
privateString trackType;
}
@Component
publicclassDriver{
privateString name;
privateString team;
privateint yearsExperience;
}
Then we remove the actual instantiation code from RaceRound, instead using
the @Autowired annotation:
publicclassRaceRound{
privateString startTime;
@Autowired
privateRaceTrack currentRaceTrack;
@Autowired
privateDriver currentDriver;
}
Notice we are no longer using the new keyword when creating instances
of RaceTrack and Driver. So, how are we able to declare and use an instance without
instantiating it?
We marked our dependent classes RaceTrack and Driver as Spring beans, which
allows the IoC container to manage them, i.e. instantiate them and inject them into
our RaceRound class.
was the @Component annotation. There is an additional, older way to do this with
XML configuration, but we’ll focus on the more modern annotations approach.
Auto-beans loading…
• @Configuration, which notifies the framework that beans may be created via
the annotated class.
• @ComponentScan, which tells the framework to scan our code for
components such as classes, controllers, services, etc.
• @EnableAutoConfiguration, which tells the container to auto-create beans
from the found components.
Using three separate annotations may seem hard to recall. However, remember when
we said “the Spring framework abstracts the complexity away with simple, easy-to-
use annotations”? This remains true as these three significant annotations have been
wrapped up into one.
You can find this annotation provided in most default Spring projects:
@SpringBootApplication
[Link]([Link], args);
}
CLOUD COMPUTING FULL STACK DEVELOPMENT-MVJ22CS61
Now let’s take a look at what happens during the bean creation process.
We are familiar with the notion of classes containing properties and methods. The
Spring framework represents beans as a BeanDefinition object. The BeanDefinition
object has several properties, but two are particularly interesting. There is a property
named class and there is a property named properties.
When we define classes, we give them a particular name, such as RaceRound. When
the container instantiates a bean from this class it populates the class property of that
bean with the fully qualified name we have provided. So, if the fully qualified name
of our class is [Link], the class property of the bean
becomes [Link]. The class property is Spring’s
way of representing the bean’s underlying Java type so it knows what to instantiate.
The properties property of the bean is populated from the properties of our class. If we
have used a built-in type such as an int or a string, the container converts the property
of our class into the same type of property for the bean. However, if we have used a
custom type, such as RaceTrack or Driver, this is a dependency and the container now
has to create a BeanDefinition object for each of these types as well. Ultimately, the
classes we create become part of a recipe for the container to use when creating beans.
When a class encapsulates other objects, the referenced objects become a dependency
for the outer class. In other words, these other objects must be created so the outer
class can use it. The container takes a look at our classes and, depending on the
method you choose, instantiates beans from the referenced objects (RaceTrack and
Driver) before it instantiates a bean from the outer classes (RaceRound). Spring
implements a way for the objects needed by another object to be provided as beans for
others to reference. This process is known as dependency injection; Our classes no
longer have to instantiate their own dependencies. Therefore, we can say the control
CLOUD COMPUTING FULL STACK DEVELOPMENT-MVJ22CS61
of dependencies has been inverted back to the container, and this is why we call it an
Inversion of Control (IoC) container.
[Link] = coffeeRepo;
Spring Container is the "Core Part" or say "Heart " of the Spring Framework which is
responsible for creation, configuration and managing the lifecycle of beans (objects)
It follows the IoC (Inversion of Control) principle by injecting dependencies
automatically, reducing tight coupling between components.
It reads configuration metadata (XML, annotations, or Java config) to know how to
manage the beans.
9. Environment Management :
• Spring Container provides support for property sources and profiles for
environment-specific configurations.
1. Java Classes : Java classes (like POJO's & JavaBean's) are used to create
simple Java objects that represent components or beans in the application.
They contain business logic, but are independent of the Spring framework.
2. Configuration Metadata : Configuration files (like XML files, Java-based
configuration classes or annotations) provide the metadata which specifies:
1. Which classes to instantiate as beans.
2. How beans are wired together (dependency injection)
3. The lifecycle and scope of each bean.
3. Spring Container :
1. The Spring Container reads the configuration metadata and scans the
specified classes.
2. It then instantiates and configures the required beans, applying
dependency injection as specified.
3. The container manages the lifecycle of these beans, creating them as
needed and handling initialization, dependencies, and destruction.
4. Bean Objects : The container creates and stores instances of beans based on
the configuration. These are the fully managed objects that can be injected or
retrieved throughout the application.
5. Accessing Beans : Once created, these bean objects are accessible throughout
the application. They can be injected into other components or accessed on
demand using dependency injection or by looking up beans from the container.
CLOUD COMPUTING FULL STACK DEVELOPMENT-MVJ22CS61
1. BeanFactory
2. ApplicationContext
"BeanFactory" Container:
BeanFactory Container creates the beans when they are requested and this concept is
known as Lazy Initialization.
"ApplicationContext" Container
ApplicationContext Container creates the beans during container startup and this
concept is known as Eager Initialization.
These are only some common configurations that we provide in spring applications.
As you keep reading further and creating more programs, you will understand these
configurations more deeply...!!
1. XML-based Configuration
@Configuration
publicclassAppConfig{
@Bean
publicStudentstdId()
{
CLOUD COMPUTING FULL STACK DEVELOPMENT-MVJ22CS61
returnnewStudent("Deepak");
}}
3. Annotations-based Configuration
@Component
publicclassStudent{
privateString name ="Deepak";}
//-----------
@Autowired
privateStudent student;
o
o Advantages: Annotations Based Configurations requires minimal
configurations, making it suitable for simpler applications or services.
It promotes cleaner code by removing external configuration files.
o Disadvantages: Annotations Based Configurations have limited
flexibility for complex bean [Link] are less explicit, which
may be confusing in large projects with numerous dependencies
Introduction
• In Spring, beans are the backbone of our application. They represent the
objects that we have to create and manage within the Spring context.
• These beans go through a well-defined life cycle, where Spring handles
everything from their creation to their destruction.
• Different stages of Bean Life Cycle are as below :-
1. Loading Bean Definitions : Spring reads the configuration (XML,
Java, or annotations) to understand how to create and configure beans,
including their properties and dependencies.
2. Bean Instantiation : Spring creates bean instances using constructors
or factory methods. Then dependencies are injected through
constructor OR setter OR property injection.
3. Bean Initialization : After bean is instantiated and its properties are
set, Spring performs initialization by calling an init() method OR
afterPropertiesSet() method (from the InitializingBean interface) OR
@PostConstruct annotation.
4. Bean Usage : The fully initialized bean is now ready for use. It can
interact with other beans or components in the application.
5. Bean Destruction : Upon container shutdown, Spring destroys the
bean. This can be done via custom destroy() method OR
DisposableBean (interface) OR @PreDestroy annotation for cleanup.
• What Happens: Spring first reads and understands the definitions of all the
beans in the application. These definitions are like blueprints that tell Spring
how to create and configure beans.
• Where Definitions Come From: These configurations can be provided by
different ways as below:
o XML Configuration: In the old days, beans were defined in XML
files.
o Java Configuration: With the rise of Java-based configuration, we
can define beans using @Configuration and @Bean annotations.
o Annotations: With annotations like @Component, @Service, etc., we
can let Spring automatically discover and register beans.
• What Spring Understands: In this stage, Spring knows the class of each
bean, its properties (like name, rollno, emailid in Student class) and its
dependencies (other beans it needs).
CLOUD COMPUTING FULL STACK DEVELOPMENT-MVJ22CS61
2. Bean Instantiation :
• What Happens: Once Spring knows what beans it needs to create, it creates
instances of those beans. This is the instantiation phase.
• How Beans Are Created: Beans can be created by different ways as below:
o Default Constructor: A no-argument constructor is used.
o Static Factory Method: A static method on a class that returns an
instance of the bean.
o Instance Factory Method: A non-static method on a separate factory
class.
• Dependency Injection: During instantiation, dependencies are injected into
the bean. This can be done in three ways:
3. Bean Initialization :
• Example: Here the bean is prepared for use. This includes setting properties
(if not already done in instantiation), performing validation, setting up
database connections, initializing caches, configuring logging, and executing
any custom initialization logic such as loading configuration files or
establishing network connections.
• Additional Functionality:
4. Bean Usage :
• What Happens: Now that the bean is initialized, it’s ready to be used. Other
beans or components in the Spring application can access and use this bean.
The bean is fully functional and serves its purpose in the application.
5. Bean Destruction :
• What Happens: When the application shuts down or the Spring container is
closed, Spring cleans up by destroying the beans.
• How Beans Are Destroyed:
• Optional Aspects: If the bean doesn't require any special clean-up, Spring
will skip these methods.
DI Introduction
Purpose of DI
• The primary goal of DI is to decouple classes from each other, making them
easier to manage, test, and reuse.
• Decoupling classes means reducing or removing direct dependencies between
them. In other words, classes don’t directly depend on specific
implementations of other classes but rely on abstractions or interfaces instead.
This separation allows each class to function independently, making the code
more flexible, modular, and easier to maintain.
When classes are decoupled, changes in one class (such as updating or
replacing it) are less likely to impact other classes, which helps in testing,
managing and reusing code across different parts of the application.
Advantages of DI
CLOUD COMPUTING FULL STACK DEVELOPMENT-MVJ22CS61
DI Mechanisms
DI Mechanisms means different ways by which dependencies are injected into beans.
Spring provides three DI mechanisms which are as follows:
1. Constructor Injection:
2. Setter Injection:
package [Link];
import [Link];
// Constructor
public Address() {}
// Getters
return city;
return state;
@Override
}}
"Student" class annotated with @Component and used @Autowired for dependency
on Address.
[Link]
[Link];
[Link];importor
[Link];
@Component
publicclassStudent{
// Constructor Injection
publicStudent(Address address)
[Link] = address;
// Getter methods
publicStringgetName()
return name;
}
CLOUD COMPUTING FULL STACK DEVELOPMENT-MVJ22CS61
publicAddressgetAddress()
return address;
@Override
publicStringtoString()
}}
[Link]
[Link];
[Link];importor
[Link];
@Configuration
@ComponentScan(basePackages="[Link]")
publicclassAppConfig{
[Link]
CLOUD COMPUTING FULL STACK DEVELOPMENT-MVJ22CS61
[Link];
[Link];
[Link]
tionContext;
[Link];[Link];
publicclassMainApp{
publicstaticvoidmain(String[] args)
ApplicationContextcontext=newAnnotationConfigApplicationC
ontext([Link]);
[Link](student);
}}
Output:
Introduction
Program 1
[Link]
[Link];
[Link];
@ComponentpublicclassEngine{
publicvoidstart()
[Link]("Engine started...");
}}
[Link]
[Link];
[Link];
@ComponentpublicclassCar{
CLOUD COMPUTING FULL STACK DEVELOPMENT-MVJ22CS61
privateEngine engine;
publicCar(Engine engine)
[Link] = engine;
publicvoiddrive()
[Link]();
[Link]("Car is running...");
}}
NOTE : Its good practice to use final keyword for fields (private final Engine
engine;) that should not change after initialization, especially for dependencies
injected via constructor injection.
[Link]
[Link];
[Link];[Link];[Link]
[Link];[Link]
Scan;[Link];
@Configuration@ComponentScan(basePackages
="[Link]")publicclassAppConfig{
@Bean
publicEngineengine()
{
CLOUD COMPUTING FULL STACK DEVELOPMENT-MVJ22CS61
@Bean
publicCarcar()
}}
[Link]
[Link];
[Link];[Link]
[Link];
[Link];[Link];
publicclassMainApp{
publicstaticvoidmain(String[] args)
ApplicationContext context
=newAnnotationConfigApplicationContext([Link]);
[Link]();
}}
CLOUD COMPUTING FULL STACK DEVELOPMENT-MVJ22CS61
Now we are going to create above same program for Constructor Injection using
XML Configurations.
[Link]
[Link];
publicclassEngine{
publicvoidstart()
[Link]("Engine started...");
}}
[Link]
[Link];
publicclassCar{
privatefinalEngine engine;
publicCar(Engine engine)
[Link] = engine;
}
CLOUD COMPUTING FULL STACK DEVELOPMENT-MVJ22CS61
publicvoiddrive()
[Link]();
[Link]("Car is running...");
}}
NOTE : Its good practice to use final keyword for fields (private final Engine
engine;) that should not change after initialization, especially for dependencies
injected via constructor injection.
[Link]
xmlns:xsi="[Link]
xsi:schemaLocation="[Link]
[Link]
[Link]">
</bean>
</beans>
CLOUD COMPUTING FULL STACK DEVELOPMENT-MVJ22CS61
NOTE : Here we have used <constructor-arg ref="----" /> tag for Constructor
Injection.
[Link]
[Link];
[Link];[Link]
[Link];
[Link];
publicclassMainApp{
publicstaticvoidmain(String[] args)
ApplicationContext context
=newClassPathXmlApplicationContext("in/sp/resources/[Link]
");
[Link]();
}}
Introduction
• In Setter Method Injection, dependencies are passed via public setter methods,
making them optional and allowing flexibility in providing or changing
dependencies after the object has been created.
• This approach allows dependencies to be injected or modified after
instantiation. If a dependency is not supplied, the object can still be created but
might not function fully until all necessary dependencies are set.
Program 1
First we will create program using Java Configurations. In this example we will take 2
classes i.e. Engine & Car. The Car class depends on the Engine class and The Engine
is injected via setter method in Car class.
[Link];
[Link];
@Component
publicclassEngine{
publicvoidstart()
[Link]("Engine started...");
}}
•
CLOUD COMPUTING FULL STACK DEVELOPMENT-MVJ22CS61
[Link]
[Link];
[Link];
@ComponentpublicclassCar{
publicvoidsetEngine(Engine engine)
[Link] = engine;
publicvoiddrive()
[Link]();
[Link]("Car is running...");
}}
NOTE : Do not use final keyword for fields (i.e. private final Engine
engine;) like we used for constructor injection because the nature of final
conflicts with the behavior of setter injection.
•
CLOUD COMPUTING FULL STACK DEVELOPMENT-MVJ22CS61
[Link]
[Link];
[Link];[Link];[Link]
[Link];[Link]
[Link];[Link]
guration;
@Configuration@ComponentScan(basePackages
="[Link]")publicclassAppConfig{
@Bean
publicEngineengine()
@Bean
publicCarcar()
return car;
}}
•
CLOUD COMPUTING FULL STACK DEVELOPMENT-MVJ22CS61
[Link]
[Link];
[Link];[Link]
[Link];
[Link];[Link];
publicclassMainApp{
publicstaticvoidmain(String[] args)
ApplicationContext context
=newAnnotationConfigApplicationContext([Link]);
[Link]();
}}
Output:
Engine started...
Car is running...
CLOUD COMPUTING FULL STACK DEVELOPMENT-MVJ22CS61
Program 2
[Link]
[Link];
publicclassEngine{
publicvoidstart()
[Link]("Engine started...");
}}
[Link]
[Link];
publicclassCar{
privateEngine engine;
publicvoidsetEngine(Engine engine)
[Link] = engine;
publicvoiddrive()
CLOUD COMPUTING FULL STACK DEVELOPMENT-MVJ22CS61
[Link]();
[Link]("Car is running...");
}}
[Link]
xmlns:xsi="[Link]
xsi:schemaLocation="[Link]
[Link]
[Link]">
</bean>
</beans>
•
CLOUD COMPUTING FULL STACK DEVELOPMENT-MVJ22CS61
NOTE : Here we have used <property name="----" ref="----" /> tag for
Setter Method Injection.
[Link]
[Link];
[Link];[Link]
[Link];
[Link];
publicclassMainApp{
publicstaticvoidmain(String[] args)
ApplicationContext context
=newClassPathXmlApplicationContext("in/sp/resources/applicationCont
[Link]");
[Link]();
}}
Output:
Engine started...
Car is running...
CLOUD COMPUTING FULL STACK DEVELOPMENT-MVJ22CS61
Autowiring in Spring
Introduction
• Note : Autowiring can't be used to inject primitive and string values. It works
with reference only.
o If multiple beans of the same type are present, it can lead to ambiguity,
making dependency management harder and causing runtime errors.
CLOUD COMPUTING FULL STACK DEVELOPMENT-MVJ22CS61
o Constructor Injection :
o Setter Injection :
1. XML-based Configuration:
Introduction
• Now we will create some programs of Autowiring using Java & Annotation
based Configuration.
Program 1
First we will create program using Java Configurations with @Autowired Annotation
which is applied on constructor.
[Link]
[Link];
publicclassEngine{
publicvoidstart()
[Link]("Engine started...");
}}
[Link]
[Link];
CLOUD COMPUTING FULL STACK DEVELOPMENT-MVJ22CS61
[Link];[Link]
[Link];
@ComponentpublicclassCar{
privateEngine engine;
@Autowired
publicCar(Engine engine)
[Link] = engine;
publicvoiddrive()
[Link]();
[Link]("Car is running...");
}}
[Link]
[Link];
[Link];[Link].
[Link];[Link]
[Link];
[Link];
@Configuration@ComponentScan(basePackages
="[Link]")publicclassAppConfig{
CLOUD COMPUTING FULL STACK DEVELOPMENT-MVJ22CS61
@Bean
publicEngineengine()
returnnewEngine();
}}
[Link]
[Link];
[Link];[Link]
[Link];
[Link];[Link];
publicclassMainApp{
publicstaticvoidmain(String[] args)
ApplicationContext context
=newAnnotationConfigApplicationContext([Link]);
[Link]();
}}
Output:
Engine started...
Car is running...
Program 2
[Link]
[Link];
publicclassEngine{
publicvoidstart()
[Link]("Engine started...");
}}
[Link]
[Link];
[Link];[Link]
[Link];
@ComponentpublicclassCar{
privateEngine engine;
@Autowired
publicvoidsetEngine(Engine engine)
[Link] = engine;
CLOUD COMPUTING FULL STACK DEVELOPMENT-MVJ22CS61
publicvoiddrive()
[Link]();
[Link]("Car is running...");
}}
[Link]
[Link];
[Link];[Link].
[Link];[Link]
[Link];
[Link];
@Bean
publicEngineengine()
returnnewEngine();
}}
[Link]
[Link];
[Link];[Link]
[Link];
[Link];
CLOUD COMPUTING FULL STACK DEVELOPMENT-MVJ22CS61
publicclassMainApp{
publicstaticvoidmain(String[] args)
ApplicationContext context
=newClassPathXmlApplicationContext("in/sp/resources/[Link]
");
[Link]();
}}
[Link]
[Link];
publicclassEngine{
publicvoidstart()
[Link]("Engine started...");
}}
CLOUD COMPUTING FULL STACK DEVELOPMENT-MVJ22CS61
[Link]
[Link];
[Link];[Link]
[Link];
@ComponentpublicclassCar{
@Autowired
publicvoiddrive()
[Link]();
[Link]("Car is running...");
}}
[Link]
[Link];
[Link];[Link].
[Link];[Link]
[Link];
[Link];
@Configuration@ComponentScan(basePackages
="[Link]")publicclassAppConfig{
@Bean
publicEngineengine()
returnnewEngine();
CLOUD COMPUTING FULL STACK DEVELOPMENT-MVJ22CS61
}}
[Link]
[Link];
[Link];[Link]
[Link];
[Link];[Link];
publicclassMainApp{
publicstaticvoidmain(String[] args)
ApplicationContext context
=newAnnotationConfigApplicationContext([Link]);
[Link]();
}}
Commonly used Spring Boot annotations along with their uses and
examples
Example:
@SpringBootApplicationpublicclassMyApplication{
publicstaticvoidmain(String[] args){
[Link]([Link], args);
}}
Example:
@RestController
publicclassMyController{
@GetMapping("/hello")
publicStringhello(){
return"Hello, World!";
}}
Example:
CLOUD COMPUTING FULL STACK DEVELOPMENT-MVJ22CS61
@RestController
@RequestMapping("/api")
publicclassMyController{
@GetMapping("/hello")
publicStringhello(){
return"Hello, World!";
}}
Example:
@ServicepublicclassMyService{
privateMyRepository repository;
@Autowired
publicMyService(MyRepository repository){
[Link] = repository;
}}
@ComponentpublicclassMyComponent{
// ...}
Example:
@Service
publicclassMyService{
// ...}
Example:
@Repository
publicclassMyRepository{
// ...}
Example:
@Configuration
publicclassMyConfiguration{
@Bean
publicMyServicemyService(){
returnnewMyService();
}}
9). @Value: This annotation is used to inject values from properties files
or other sources into Spring beans.
Example:
CLOUD COMPUTING FULL STACK DEVELOPMENT-MVJ22CS61
@Component
publicclassMyComponent{
@Value("${[Link]}")
privateString myProperty;}
Example:
@SpringBootApplication
@EnableAutoConfiguration
publicclassMyApplication{
// ...}
Example:
@RestController
@RequestMapping("/api")
publicclassMyController{
@GetMapping("/hello")
publicStringhello(){
return"Hello, World!";
CLOUD COMPUTING FULL STACK DEVELOPMENT-MVJ22CS61
@PostMapping("/data")
publicvoidsaveData(@RequestBodyData data){
// Save data
}}
Example:
@RestController@RequestMapping("/api")publicclassMyController{
@GetMapping("/users/{id}")
publicUsergetUser(@PathVariableLong id){
}}
Example:
@RestController@RequestMapping("/api")publicclassMyController{
@GetMapping("/users")
publicList<User>getUsers(@RequestParam("status")String status){
}}
CLOUD COMPUTING FULL STACK DEVELOPMENT-MVJ22CS61
@RestController@RequestMapping("/api")publicclassMyController{
@PostMapping("/users")
publicvoidcreateUser(@RequestBodyUser user){
}}
Example:
@Service@Qualifier("myService")publicclassMyService{
// ...}
@ServicepublicclassAnotherService{
@Autowired
@Qualifier("myService")
privateMyService myService;
// ...}
Example:
@Configuration@ConditionalOnProperty(name ="[Link]",
havingValue ="true")publicclassMyConfiguration{
CLOUD COMPUTING FULL STACK DEVELOPMENT-MVJ22CS61
Example:
@ComponentpublicclassMyScheduler{
@Scheduled(fixedDelay =5000)
publicvoiddoSomething(){
}}
Example:
@ServicepublicclassMyService{
@Cacheable("users")
publicUsergetUserById(Long id){
@CachePut("users")
publicUserupdateUser(User user){
}
CLOUD COMPUTING FULL STACK DEVELOPMENT-MVJ22CS61
@CacheEvict("users")
publicvoiddeleteUser(Long id){
}}
1. Core Annotations:
a). @SpringBootApplication
Example:
@SpringBootApplicationpublicclassMyApp{
publicstaticvoidmain(String[] args){
[Link]([Link], args);
}}
b). @ComponentScan
Example:
@ComponentScan("[Link]")@ConfigurationpublicclassA
ppConfig{
c). @Configuration
d). @EnableAutoConfiguration
e). @RestController
f). @Controller
CLOUD COMPUTING FULL STACK DEVELOPMENT-MVJ22CS61
g). @Service
h). @Repository
i). @Bean
j). @Autowired
CLOUD COMPUTING FULL STACK DEVELOPMENT-MVJ22CS61
k). @Qualifier
l). @Value
2. Web Annotations:
@RequestMapping
@GetMapping
@PostMapping
@PutMapping
@DeleteMapping
@PatchMapping
@RequestBody
CLOUD COMPUTING FULL STACK DEVELOPMENT-MVJ22CS61
@ResponseBody
@PathVariable
@RequestParam
@RequestHeader
@CookieValue
@ModelAttribute
@ResponseStatus
@ExceptionHandler
3. Data Annotations:
@Entity
@Table
@Id
@GeneratedValue
@Column
@Transient
@Repository
@Service
@Transactional
@PersistenceContext
CLOUD COMPUTING FULL STACK DEVELOPMENT-MVJ22CS61
@Autowired
@Query
@NamedQuery
@Param
@JoinTable
@JoinColumn
4. Validation Annotations:
@Valid
@NotNull
@Size
@Min
@Max
@Pattern
5. Security Annotations:
@EnableWebSecurity
@Configuration
@EnableGlobalMethodSecurity
@PreAuthorize
CLOUD COMPUTING FULL STACK DEVELOPMENT-MVJ22CS61
@PostAuthorize
@Secured
@RolesAllowed
@EnableOAuth2Client
@EnableResourceServer
@EnableAuthorizationServer
6. Testing Annotations:
@RunWith
@SpringBootTest
@WebMvcTest
@DataJpaTest
@RestClientTest
@MockBean
@AutoConfigureMockMvc
@Test
@Before
@After
@BeforeEach
@AfterEach
CLOUD COMPUTING FULL STACK DEVELOPMENT-MVJ22CS61
@BeforeAll
@AfterAll
@DisplayName
@Disabled
@ParameterizedTest
@ValueSource
@CsvSource
@ExtendWith
7. Caching Annotations:
@EnableCaching
@Cacheable
@CachePut
@CacheEvict
@Caching
8. Scheduling Annotations:
@EnableScheduling
@Scheduled
9. Messaging Annotations:
@EnableJms
CLOUD COMPUTING FULL STACK DEVELOPMENT-MVJ22CS61
@JmsListener
@SendTo
@MessageMapping
@Payload
@Header
@Aspect
@Pointcut
@Before
@After
@AfterReturning
@AfterThrowing
@Around
@EnableActuator
@Endpoint
@RestControllerEndpoint
@ReadOperation
@WriteOperation
CLOUD COMPUTING FULL STACK DEVELOPMENT-MVJ22CS61
@DeleteOperation
@ConfigurationProperties
@ConstructorBinding
@Validated
@EnableMessageSource
@EnableWebMvc
@LocaleResolver
@MessageBundle
@MessageSource
@Slf4j
@Log4j2
@Log
@Timed
@Counted
@ExceptionMetered
@Validated
@Valid
@Validated
@NotNull
@NotBlank
@Size
@Pattern
@Positive
@PositiveOrZero
@Negative
@NegativeOrZero
@GraphQLApi
@GraphQLQuery
@GraphQLMutation
@GraphQLSubscription
@GraphQLArgument
@GraphQLContext
CLOUD COMPUTING FULL STACK DEVELOPMENT-MVJ22CS61
@GraphQLNonNull
@GraphQLInputType
@GraphQLType
@IntegrationComponentScan
@MessagingGateway
@Transformer
@Splitter
@Aggregator
@ServiceActivator
@InboundChannelAdapter
@OutboundChannelAdapter
@Router
@BridgeTo
@FlywayTest
@FlywayTestExtension
@[Link]
@[Link]
CLOUD COMPUTING FULL STACK DEVELOPMENT-MVJ22CS61
@[Link]
@ExtendWith
@TestInstance
@TestTemplate
@DisplayNameGeneration
@Nested
@Tag
@DisabledOnOs
@EnabledOnOs
@DisabledIf
@EnabledIf
java
import [Link];
import [Link];
@Configuration
public class AppConfig {
@Bean
public MyService myService() {
return new MyServiceImpl();
}
@Bean
public MyController myController() {
return new MyController(myService());
}}
Annotate your classes with @Component to indicate that they are Spring beans:
java
import [Link];
@Component
public class MyComponent {
// your logic here}
java
CLOUD COMPUTING FULL STACK DEVELOPMENT-MVJ22CS61
import [Link];
import [Link];
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
[Link]([Link], args);
}}
java
import [Link];
import [Link];
@Component
public class MyServiceConsumer {
private final MyService myService;
@Autowired
public MyServiceConsumer(MyService myService) {
[Link] = myService;
}
// use myService in your methods}
RESTful Web Services
RESTful Web Services REST stands for REpresentational State Transfer. It was
developed by Roy Thomas Fielding, one of the principal authors of the web
protocol HTTP. Consequently, REST was an architectural approach designed to
make the optimum use of HTTP protocol. It uses the concepts and verbs already
present in HTTP to develop web services. This made REST incredibly easy to use
and consume, so much so that it is the go-to standard for building web services
today.
1. GET
The default request method for HTTP. We don’t have any request body with this
method, but we can define multiple request parameters or path variables in the URL.
This method is used for getting obtaining some resources. Depending on the
presence of an ID parameter, either we can fetch a specific resource or fetch a
collection of resources in the absence of the parameter. Sample GET request in
Spring Boot Controller:
@GetMapping("/user/{userId}")
public ResponseEntity<Object> getUser(@PathVariable int userId) {
UserEntity user = [Link](userId);
return new ResponseEntity<>(user, [Link]);
}
2. POST
The POST method of HTTP is used to create a resource. We have a request body in
this method and can also define multiple request parameters or path variables in the
URL. Sample POST request in Spring Boot Controller:
@PostMapping(value = "/user")
public ResponseEntity<Object> addUser(@RequestBody UserEntity user) {
[Link](user);
return new ResponseEntity<>("User is created successfully",
[Link]);
}
3. PUT
The PUT method of HTTP is used to update an existing resource. We have a request
body in this method and can also define multiple request parameters or path
variables in the URL. Sample PUT request in Spring Boot Controller:
@PutMapping("/user/{userId}")
public ResponseEntity<Object> getUser(@RequestBody UserEntity user) {
[Link](user);
return new ResponseEntity<>("User is updated successfully", [Link]);
}
4. DELETE
@DeleteMapping(value = "/user")
public ResponseEntity<Object> addUser(@PathVariable int userId) {
[Link](userId);
return new ResponseEntity<>("User is deleted successfully", [Link]);
}
• 200: Success
• 201: Created
• 401: Unauthorized
• 404: Resource Not Found
• 500: Server Error
Principles of RESTful web services
The following are the main principles rest services follow, which makes them fast,
lightweight, and secure are:
• Easy to Build: REST APIs are simpler to build than a corresponding SOAP
API. Hence, REST is the better choice if we want to develop APIs quickly.
• Independent: Since the client and server are decoupled in RESTful web
services, it allows for independent development across projects.
• Scalability: Stateless communication and a replicated repository provide a
high level of scalability. Compared to SOAP, scaling up an existing website is
easier with the REST web services.
• Layered System: REST web services have their application divided into
multiple layers forming a hierarchy. It makes the application both modular and
scalable.
Consuming REST Services in Spring Boot
Spring Boot provides several robust options for consuming RESTful web services. In
this blog post, we will explore three primary methods: RestTemplate, WebClient, and
Feign Client. Each approach offers unique features and benefits suited for different
use cases.
1. RestTemplate
Description: RestTemplate is a synchronous client for performing HTTP requests. It
is simple to use and ideal for applications where synchronous calls are sufficient.
Synchronous client:
This means that the client waits for a response from the server before proceeding with
the next action.
<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
Configuration: Configure RestTemplate as a bean:
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
return [Link]();
}
}
Service Implementation: Use RestTemplate in your service class:
@Service
public class RestTemplateService {
private final RestTemplate restTemplate;
<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
@Configuration
public class WebClientConfig {
@Bean
public [Link] webClientBuilder() {
return [Link]();
}
}
Service Implementation: Use WebClient in your service class:
@Service
public class WebClientService {
private final WebClient webClient;
Add Dependency: To use Feign, add the following dependency to your [Link]:
<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
Enable Feign Clients: Enable Feign clients in your main application class:
@SpringBootApplication
@EnableFeignClients
public class Application {
public static void main(String[] args) {
[Link]([Link], args);
}
}
Define Feign Client: Define the Feign client interface:
@Service
public class FeignClientService {
private final ApiClient apiClient;
Hibernate Validator
[Link] Validation Dependency
[Link] Validation Constraints in DTO.
[Link] Request Data in Controller
[Link] Validation Error Responses
Dependencies
To use the validation framework in our application we need to add following
dependencies to our project.
<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
Bean Validation
Bean Validation works by adding constraint annotations on the fields of the class to
be validated. Commonly used annotations are defined in [Link]
package.
[Link] Body
[Link] Variables
[Link] Parameters
[Link]:
Implementing Validations on the Bean
<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
Let’s add a few validations to the Student bean. We are using @Size to specify the
minimum length and also a message when a validation error occurs.
@Entity
@Id
@GeneratedValue
@NotNull
@NotNull
@Size(min=7, message="Passport should have atleast 2 characters")
• The @Valid annotation ensures that the Student object is validated against the
constraints specified in the Student class before the controller's logic is executed.
• If validation fails (e.g., a field does not meet the constraints), Spring will throw a
MethodArgumentNotValidException. You can handle this exception globally to
return custom error messages
@Entity Annotation
This marks the Student class as a JPA Entity, meaning it maps to a table in a
database.
• By default, the table name corresponds to the class name (Student), but you can
customize it using the @Table annotation.
• @Id: Specifies that the id field is the primary key of the Student entity.
• message: The custom message returned to the client when validation fails.
The @GeneratedValue annotation in Java's JPA (Java Persistence API) is used to specify how the
primary key (annotated with @Id) of an entity should be automatically generated
Simple. Add @Valid in addition to @RequestBody.
It automatically converts JSON or XML data from the request body into a Java object
When you execute a request with attributes not matching the constraint, you get a 404
BAD Request status back.
Request
"name": "",
"passportNumber": "A12345678"
@ControllerAdvice
@RestController
@Override
protected ResponseEntity<Object>
handleMethodArgumentNotValid(MethodArgumentNotValidException ex,
[Link]().toString());
Parameters:
HttpStatus status: The HTTP status code (in this case, 400 BAD REQUEST).
@ControllerAdvice
@RestController
[Link](false));
When you execute a request with attributes not matching the constraint, you get a 404
BAD Request status back.
Request
"name": "",
"passportNumber": "A12345678"
"timestamp": 1512717715118,
"message": "Validation Failed",
"details": "[Link]: 1
errors\nField error in object 'student' on field 'name': rejected value []; codes
[[Link],[Link],[Link],Size]; arguments
[[Link]: codes
[[Link],name]; arguments []; default message [name],2147483647,2]; default
message [Name should have atleast 2 characters]"
[Link]
the @PathVariable annotation can be used to handle template variables in the
request URI mapping, and set them as method parameters.
A simple use case of the @PathVariable annotation would be an endpoint that
identifies an entity with a primary key:
@GetMapping("/api/employees/{id}")
@ResponseBody
In this example, we use the @PathVariable annotation to extract the templated part of
the URI, represented by the variable {id}.
[Link]
----
ID: 111
However, if the path variable name is different, we can specify it in the argument of
the @PathVariable annotation:
@GetMapping("/api/employeeswithvariable/{id}")
@ResponseBody
Depending on the use case, we can have more than one path variable in our
request URI for a controller method, which also has multiple method parameters:
@GetMapping("/api/employees/{id}/{name}")
@ResponseBody
}
[Link]
----
We can also handle more than one @PathVariable parameter using a method
parameter of type [Link]<String, String>:
@GetMapping("/api/employeeswithmapvariable/{id}/{name}")
@ResponseBody
String id = [Link]("id");
} else {
@GetMapping(value = { "/api/employeeswithrequired",
"/api/employeeswithrequired/{id}" })
@ResponseBody
[Link]
----
ID: 111
[Link] ParAmeter:
Configuration
<dependency>
<groupId>[Link]</groupId>
<artifactId>hibernate-validator</artifactId>
<version>[Link]</version>
</dependency>
We also have to enable validation for both request parameters and path
variables in our controllers by adding the @Validated annotation:
@RestController
@RequestMapping("/")
@Validated
public class RequestAndPathVariableValidationController {
// ...
}
It’s important to note that enabling parameter validation also requires
a MethodValidationPostProcessor bean. If we’re using a Spring Boot application,
then this bean is auto-configured, as we have the hibernate-validator dependency on
our classpath.
@EnableWebMvc
@Configuration
@ComponentScan("[Link]")
public class ClientWebConfigJava implements WebMvcConfigurer {
@Bean
public MethodValidationPostProcessor methodValidationPostProcessor() {
return new MethodValidationPostProcessor();
}
// ...
}
By default, any error during path or request validation in Spring results in an HTTP
500 response. In this tutorial, we’ll use a custom implementation
of ControllerAdvice to handle these kinds of errors in a more readable way, returning
an HTTP 400 for any bad request.
Validating a RequestParam
Let’s consider an example where we pass a numeric weekday into a controller method
as a request parameter.
@GetMapping("/name-for-day")
public String getNameOfDayByNumberRequestParam(@RequestParam Integer
dayOfWeek) {
// ...
}
Our goal is to make sure that the value of dayOfWeek is between 1 and 7. To do so,
we’ll use the @Min and @Max annotations:
@GetMapping("/name-for-day")
public String getNameOfDayByNumberRequestParam(@RequestParam @Min(1)
@Max(7) Integer dayOfWeek) {
// ...
}
Any request that doesn’t match these conditions will return an HTTP status 400 with a
default error message.
Validating a PathVariable
Let’s consider an example where we validate that a String parameter isn’t blank and
has a length of less than or equal to 10:
@GetMapping("/valid-name/{name}")
public void validStringRequestParam(@PathVariable("name") @NotBlank
@Size(max = 10) String username) {
// ...
}
Any request with a name parameter longer than 10 characters, for instance, will result
in an HTTP 400 error with a message:
Component Purpose
DTO Classes Define structure and constraints for incoming requests.
Component Purpose
Validation Add constraints like @NotBlank, @NotNull, @Size, etc., to fields for
Annotations validation.
@ControllerAdvice Handle validation exceptions globally and return custom responses.
Use @Valid to enable validation and process requests using the validated
Controllers DTOs
RESTful Web Services
RESTful Web Services REST stands for REpresentational State Transfer. It was
developed by Roy Thomas Fielding, one of the principal authors of the web
protocol HTTP. Consequently, REST was an architectural approach designed to
make the optimum use of HTTP protocol. It uses the concepts and verbs already
present in HTTP to develop web services. This made REST incredibly easy to use
and consume, so much so that it is the go-to standard for building web services
today.
1. GET
The default request method for HTTP. We don’t have any request body with this
method, but we can define multiple request parameters or path variables in the URL.
This method is used for getting obtaining some resources. Depending on the
presence of an ID parameter, either we can fetch a specific resource or fetch a
collection of resources in the absence of the parameter. Sample GET request in
Spring Boot Controller:
@GetMapping("/user/{userId}")
public ResponseEntity<Object> getUser(@PathVariable int userId) {
UserEntity user = [Link](userId);
return new ResponseEntity<>(user, [Link]);
}
2. POST
The POST method of HTTP is used to create a resource. We have a request body in
this method and can also define multiple request parameters or path variables in the
URL. Sample POST request in Spring Boot Controller:
@PostMapping(value = "/user")
public ResponseEntity<Object> addUser(@RequestBody UserEntity user) {
[Link](user);
return new ResponseEntity<>("User is created successfully",
[Link]);
}
3. PUT
The PUT method of HTTP is used to update an existing resource. We have a request
body in this method and can also define multiple request parameters or path
variables in the URL. Sample PUT request in Spring Boot Controller:
@PutMapping("/user/{userId}")
public ResponseEntity<Object> getUser(@RequestBody UserEntity user) {
[Link](user);
return new ResponseEntity<>("User is updated successfully", [Link]);
}
4. DELETE
@DeleteMapping(value = "/user")
public ResponseEntity<Object> addUser(@PathVariable int userId) {
[Link](userId);
return new ResponseEntity<>("User is deleted successfully", [Link]);
}
200: Success
201: Created
401: Unauthorized
404: Resource Not Found
500: Server Error
Principles of RESTful web services
The following are the main principles rest services follow, which makes them fast,
lightweight, and secure are:
Easy to Build: REST APIs are simpler to build than a corresponding SOAP
API. Hence, REST is the better choice if we want to develop APIs quickly.
Independent: Since the client and server are decoupled in RESTful web
services, it allows for independent development across projects.
Scalability: Stateless communication and a replicated repository provide a
high level of scalability. Compared to SOAP, scaling up an existing website is
easier with the REST web services.
Layered System: REST web services have their application divided into
multiple layers forming a hierarchy. It makes the application both modular and
scalable.
Consuming REST Services in Spring Boot
Spring Boot provides several robust options for consuming RESTful web services. In
this blog post, we will explore three primary methods: RestTemplate, WebClient, and
Feign Client. Each approach offers unique features and benefits suited for different
use cases.
1. RestTemplate
Description: RestTemplate is a synchronous client for performing HTTP requests. It
is simple to use and ideal for applications where synchronous calls are sufficient.
Synchronous client:
This means that the client waits for a response from the server before proceeding with
the next action.
<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
Configuration: Configure RestTemplate as a bean:
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
return [Link]();
}
}
Service Implementation: Use RestTemplate in your service class:
@Service
public class RestTemplateService {
private final RestTemplate restTemplate;
<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
@Configuration
public class WebClientConfig {
@Bean
public [Link] webClientBuilder() {
return [Link]();
}
}
Service Implementation: Use WebClient in your service class:
@Service
public class WebClientService {
private final WebClient webClient;
Add Dependency: To use Feign, add the following dependency to your [Link]:
<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
Enable Feign Clients: Enable Feign clients in your main application class:
@SpringBootApplication
@EnableFeignClients
public class Application {
public static void main(String[] args) {
[Link]([Link], args);
}
}
Define Feign Client: Define the Feign client interface:
@Service
public class FeignClientService {
private final ApiClient apiClient;
Hibernate Validator
[Link] Validation Dependency
[Link] Validation Constraints in DTO.
[Link] Request Data in Controller
[Link] Validation Error Responses
Dependencies
To use the validation framework in our application we need to add following
dependencies to our project.
<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
Bean Validation
Bean Validation works by adding constraint annotations on the fields of the class to
be validated. Commonly used annotations are defined in [Link]
package.
[Link] Body
[Link] Variables
[Link] Parameters
[Link]:
<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
Let’s add a few validations to the Student bean. We are using @Size to specify the
minimum length and also a message when a validation error occurs.
@Entity
@Id
@GeneratedValue
@NotNull
The @Valid annotation ensures that the Student object is validated against the
constraints specified in the Student class before the controller's logic is executed.
If validation fails (e.g., a field does not meet the constraints), Spring will throw
a MethodArgumentNotValidException. You can handle this exception globally to
return custom error messages
@Entity Annotation
This marks the Student class as a JPA Entity, meaning it maps to a table in a
database.
By default, the table name corresponds to the class name (Student), but you
can customize it using the @Table annotation.
@Id: Specifies that the id field is the primary key of the Student entity.
message: The custom message returned to the client when validation fails.
It automatically converts JSON or XML data from the request body into a Java object
When you execute a request with attributes not matching the constraint, you get a 404
BAD Request status back.
Request
"name": "",
"passportNumber": "A12345678"
}
Customizing Validation Response
@ControllerAdvice
@RestController
protected ResponseEntity<Object>
handleMethodArgumentNotValid(MethodArgumentNotValidException ex,
[Link]().toString());
Parameters:
HttpStatus status: The HTTP status code (in this case, 400 BAD REQUEST).
@ControllerAdvice
@RestController
public class CustomizedResponseEntityExceptionHandler extends
ResponseEntityExceptionHandler {
@ExceptionHandler(StudentNotFoundException)
[Link](false));
When you execute a request with attributes not matching the constraint, you get a 404
BAD Request status back.
Request
"name": "",
"passportNumber": "A12345678"
{
"timestamp": 1512717715118,
"details": "[Link]: 1
errors\nField error in object 'student' on field 'name': rejected value []; codes
[[Link],[Link],[Link],Size]; arguments
[[Link]: codes
[[Link],name]; arguments []; default message [name],2147483647,2]; default
message [Name should have atleast 2 characters]"
[Link]
the @PathVariable annotation can be used to handle template variables in the
request URI mapping, and set them as method parameters.
A simple use case of the @PathVariable annotation would be an endpoint that
identifies an entity with a primary key:
@GetMapping("/api/employees/{id}")
@ResponseBody
In this example, we use the @PathVariable annotation to extract the templated part of
the URI, represented by the variable {id}.
----
ID: 111
However, if the path variable name is different, we can specify it in the argument of
the @PathVariable annotation:
@GetMapping("/api/employeeswithvariable/{id}")
@ResponseBody
Depending on the use case, we can have more than one path variable in our
request URI for a controller method, which also has multiple method parameters:
@GetMapping("/api/employees/{id}/{name}")
@ResponseBody
[Link]
----
We can also handle more than one @PathVariable parameter using a method
parameter of type [Link]<String, String>:
@GetMapping("/api/employeeswithmapvariable/{id}/{name}")
@ResponseBody
String id = [Link]("id");
} else {
@GetMapping(value = { "/api/employeeswithrequired",
"/api/employeeswithrequired/{id}" })
@ResponseBody
[Link]
----
ID: 111
3. Query Parameter:
Configuration
<dependency>
<groupId>[Link]</groupId>
<artifactId>hibernate-validator</artifactId>
<version>[Link]</version>
</dependency>
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link].*;
@RestController
@RequestMapping("/")
@Validated
public class RequestAndPathVariableValidationController {
// ✅RequestParam validation
@GetMapping("/name-for-day")
public String getNameOfDayByNumberRequestParam(
@RequestParam
@Min(value = 1, message = "Day number must be >= 1")
@Max(value = 7, message = "Day number must be <= 7") Integer
dayOfWeek) {
// ✅PathVariable validation
@GetMapping("/valid-name/{name}")
public String validStringRequestParam(
@PathVariable("name")
@NotBlank(message = "Name must not be blank")
@Size(max = 10, message = "Name must be at most 10 characters")
String username) {
return "Validated username: " + username;
}
}
OUTPUT:Wednesday
GET [Link]
JSON RESPONSE:
{
"[Link]": "Day number must be
<= 7"}
GET [Link]
INVALID REQUEST:
GET [Link]
{
"[Link]": "Name must not be blank"}
Validate Create Post and Update Post REST API Request:
import [Link].*;
import [Link];
@RestController
@RequestMapping("/posts")
public class PostController {
// CREATE POST
@PostMapping
public String createPost(@Valid @RequestBody PostRequest
postRequest) {
// service call
return "Post created successfully!";
}
// UPDATE POST
@PutMapping("/{id}")
public String updatePost(@PathVariable Long id,
@Valid @RequestBody PostRequest
postRequest) {
// service call
return "Post updated successfully!";
}
}
3. Global Exception Handling for Validation Errors
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler([Link])
public ResponseEntity<Map<String, String>>
handleValidationExceptions(
MethodArgumentNotValidException ex) {
return [Link]().body(errors);
}
}
4. Example Requests & Responses
{
"title": "Spring Boot Validation",
"content": "This is a valid post content."
}
Response:
"Post created successfully!"
Invalid Request:
POST /posts
Content-Type: application/json
{
"title": "",
"content": ""
}
Response:
{
"title": "Title is mandatory",
"content": "Content cannot be empty"
}
import [Link];
import [Link];
@RestController
@RequestMapping("/api/comments")
public class CommentController {
// UPDATE COMMENT
@PutMapping("/{id}")
public ResponseEntity<CommentDTO> updateComment(
@PathVariable Long id,
@Validated @RequestBody CommentDTO commentDTO) {
[Link](id);
CommentDTO updated = [Link](commentDTO);
return [Link](updated);
}
}
@Service
public class CommentService {
import [Link];
import [Link];
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler([Link])
public ResponseEntity<Map<String, String>>
handleValidationErrors(MethodArgumentNotValidException ex) {
Map<String, String> errors = new HashMap<>();
[Link]().getFieldErrors().forEach(error ->
[Link]([Link](), [Link]())
);
return new ResponseEntity<>(errors, HttpStatus.BAD_REQUEST);
}
}
Create Comment (Valid):
POST /api/comments
Content-Type: application/json
{
"text": "This is a valid comment with enough length.",
"author": "Seetha"
}
Response:
{
"id": 1,
"text": "This is a valid comment with enough length.",
"author": "Seetha"
}
POST /api/comments
Content-Type: application/json
{
"text": "Hi",
"author": ""
}
Response
{
"text": "Comment must be between 5 and 500 characters",
"author": "Author name is required"
}
Update Comment
PUT /api/comments/1
Content-Type: application/json
{
"text": "Updated comment text with proper length.",
"author": "Seetha"
}
Response:
{
"id": 1,
"text": "Updated comment text with proper length.",
"author": "Seetha"
}
Component Purpose
Define structure and constraints for incoming
DTO Classes
requests.
Validation Add constraints like @NotBlank, @NotNull, @Size,
Annotations etc., to fields for validation.
Handle validation exceptions globally and return
@ControllerAdvice
custom responses.
Use @Valid to enable validation and process
Controllers
requests using the validated DTOs