Skip to content

Instantly share code, notes, and snippets.

@AaradhyaSaxena
Last active May 8, 2024 13:48
Show Gist options
  • Save AaradhyaSaxena/2700451510924cccbfea734bfdef30c2 to your computer and use it in GitHub Desktop.
Save AaradhyaSaxena/2700451510924cccbfea734bfdef30c2 to your computer and use it in GitHub Desktop.
Spring

Spring Basics

The highlight of Spring Boot is its auto-configuration feature whereby it automatically includes all the dependencies of a project based on property files and JAR classpaths. Spring Boot is basically the Spring framework along with embedded servers. Spring boot removes the need for XML configuration.

Decoupling Components

public interface Filter {
    public String[] 
    getRecommendations(String movie);
}

public class ContentBasedFilter implements Filter{
    //...
}
public class CollaborativeFilter implements Filter{
    //...
}

public class RecommenderImplementation {

    //use filter interface to select filter
    private Filter filter;
            
    public RecommenderImplementation(Filter filter) {
        super();
        this.filter = filter;
    }

    //use a filter to find recommendations
    public String [] recommendMovies (String movie) {
        String[] results = filter.getRecommendations("Finding Dory");
        return results;
    }
}

@SpringBootApplication
public class MovieRecommenderSystemApplication {
	public static void main(String[] args) {
		RecommenderImplementation recommender = new RecommenderImplementation(new ContentBasedFilter());	
		String[] result = recommender.recommendMovies("Finding Dory");
	}
}

Spring automates the above process of creating objects and binding them together. It takes the responsibility of creating instances of classes and binding instances based on their dependencies. The instances or objects that Spring manages are called beans. To manage objects and dependencies, Spring requires information about three things:

  • Beans
  • Dependencies
  • Location of beans

@Component

If we want Spring to create and manage objects, we can do so by adding the @Component annotation at the beginning of the class and importing org.springframework.stereotype.Component.

For now, we want Spring to manage objects of RecommenderImplementation and ContentBasedFilter class only, so we will add the @Component annotation at two places in the code:

@Component
public class RecommenderImplementation {
    //...
}

@Component
public class ContentBasedFilter implements Filter {
    //...
}

@Autowired

In our application, the ContentBasedFilter class (which implements the Filter interface) is a dependency of the RecommenderImplementation class.

@Component
public class RecommenderImplementation {

    @Autowired
    private Filter filter;
    // ...
}

The @Autowired annotation tells Spring that RecommenderImplementation needs an object of type Filter. In other words, Filter is a dependency of RecommenderImplementation.

@ComponentScan

The third thing that Spring requires from the developer, is the location of the beans so that it can find them and autowire the dependencies. The @ComponentScan annotation is used for this purpose. This annotation can be used with or without arguments. It tells Spring to scan a specific package and all of its sub-packages.

@SpringBootApplication is equivalent to the following three annotations:

  • @Configuration, which declares a class as the source for bean definitions
  • @EnableAutoConfiguration, which allows the application to add beans using classpath definitions
  • @ComponentScan, which directs Spring to search for components in the path specified

NoUniqueBeanDefinitionException

The NoUniqueBeanDefinitionException occurs. The error message says: Required a single bean but two were found.

Autowiring By Type

@Primary

One way Spring can choose between two beans of the same type is by giving one bean priority over the other. The @Primary annotation is used for making a component the default choice when multiple beans of the same type are found. Using @Primary is called autowiring by type. We are looking for instances of type Filter. If we make both beans primary by adding the @Primary annotation to both implementations of the Filter interface, we will get an error.

Autowiring By Name

public class RecommenderImplementation {

    @Autowired
    private Filter contentBasedFilter;
 
    public String [] recommendMovies (String movie) {       
        System.out.println("\nName of the filter in use: " + contentBasedFilter + "\n");
        String[] results = contentBasedFilter.getRecommendations("Finding Dory");
        return results;
   }
}

Autowiring — @Qualifier

Like @Primary, the @Qualifier annotation gives priority to one bean over the other if two beans of the same type are found. The bean whose name is specified in the @Qualifier annotation qualifies to be injected as a dependency. The @Qualifier annotation can be used in a scenario when we have multiple objects of the same type and autowiring by name cannot be used because the variable name doesn’t match any bean name.

@Component("CBF")
public  class ContentBasedFilter implements Filter{
    //...
}
// OR
@Component
@Qualifier("CBF")
public  class ContentBasedFilter implements Filter{
    //...
}

public class RecommenderImplementation {

    @Autowired
    @Qualifier("CBF")
    private Filter filter;
 
    public String [] recommendMovies (String movie) {       
        //...
    }
}

The @Qualifier annotation takes precedence over the @Primary annotation.

@Autowired annotation resolves dependencies by type. If there are more than one beans of the same type, a conflict arises. We have seen three different approaches to resolve conflicts. They can be resolved using the @Primary annotation, renaming the variable to match the name of the class, or by using the @Qualifier annotation.

Dependency Injection

In Spring framework, there are several types of dependency injection techniques. Dependency injection is a fundamental principle of the Spring framework, which helps in achieving loose coupling between objects and their dependencies. Here are the different types of injections in Spring, their uses, pros, and cons, along with examples:

Constructor Injection:

Constructor injection is a way of injecting dependencies through a class constructor.

Example:

public class EmployeeService {
    private EmployeeRepository employeeRepository;

    public EmployeeService(EmployeeRepository employeeRepository) {
        this.employeeRepository = employeeRepository;
    }

    // Other methods
}

Pros:

  • It ensures that the required dependencies are available when the object is created.
  • It makes the class immutable since the dependencies cannot be changed once the object is constructed.

Cons:

  • It can lead to a large number of constructors if there are many dependencies.
  • It can make the code more verbose and harder to read.

Setter Injection:

Setter injection is a way of injecting dependencies by calling setter methods on the class.

Example:

public class EmployeeService {
    private EmployeeRepository employeeRepository;

    public void setEmployeeRepository(EmployeeRepository employeeRepository) {
        this.employeeRepository = employeeRepository;
    }

    // Other methods
}

Pros:

  • It provides a way to inject dependencies after the object is created.
  • It is more flexible than constructor injection, as dependencies can be changed at runtime.

Cons:

  • It can lead to partially initialized objects if dependencies are not set correctly.
  • It requires additional boilerplate code for setter methods.

Field Injection:

Field injection is a way of injecting dependencies directly into the class fields.

Example:

public class EmployeeService {
    @Autowired
    private EmployeeRepository employeeRepository;

    // Other methods
}

Pros:

  • It is concise and requires less code compared to other injection types.

Cons:

  • It violates encapsulation principles, as dependencies are directly exposed.
  • It can lead to tight coupling between classes, making it harder to unit test.
  • It is generally not recommended and should be avoided in favor of constructor or setter injection.

Method Injection:

Method injection is a way of injecting dependencies through a method parameter.

Example:

public class EmployeeService {
    private EmployeeRepository employeeRepository;

    public void setEmployeeRepository(EmployeeRepository employeeRepository) {
        this.employeeRepository = employeeRepository;
    }

    public void processEmployees(List<Employee> employees, @Qualifier("specialRepository") EmployeeRepository specialRepository) {
        // Use specialRepository for specific operations
    }
}

Pros:

  • It allows for flexible dependency injection based on method parameters.
  • It can be useful for injecting specific dependencies for certain use cases.

Cons:

  • It can make the code harder to read and maintain if overused.
  • It can lead to tight coupling between classes if not used carefully.

In general, constructor injection is considered the best practice for most cases, as it ensures that the required dependencies are available when the object is created and makes the class immutable. Setter injection can be useful in certain scenarios where dependencies need to be changed at runtime or for optional dependencies.

Field injection and method injection are generally not recommended due to potential issues with encapsulation, tight coupling, and code maintainability. However, they can be useful in specific scenarios where the benefits outweigh the drawbacks.

Screenshot 2023-06-25 at 12 48 03 PM

Spring Advanced

Bean Scope

The Spring container manages beans. The term bean scope refers to the lifecycle and the visibility of beans. It tells how long the bean lives, how many instances of the bean are created, and how the bean is shared.

Singleton scope The default scope of a bean is singleton, in which only one instance of the bean is created and cached in memory. Multiple requests for the bean return a shared reference to the same bean. In contrast, prototype scope results in the creation of new beans whenever a request for the bean is made to the application context.

Singleton bean scope is the default scope. It is used to minimize the number of objects created. Beans are created when the context is loaded and cached in memory. All requests for a bean are returned with the same memory address. This type of scope is best suited for cases where stateless beans are required. On the contrary, prototype bean scope is used when we need to maintain the state of the beans.

Spring creates a singleton bean even before we ask for it while a prototype bean is not created till we request Spring for the bean.

Mixing Bean Scope

The ContentBasedFilter bean has singleton scope because we need only one instance of the filter. However, the Movie bean has prototype scope because we need more than one objects of this class. When a prototype bean is injected into a singleton bean, it loses its prototype behavior and acts as a singleton.

@ComponentScan

In a Spring application, the @ComponentScan annotation without any argument tells Spring to scan the current package as well as any sub-packages that might exist. Spring detects all classes marked with the @Component, @Repository, @Service, and @Controller annotations during component scan.

The @SpringBootApplication annotation is a combination of three annotations:

  • @Configuration
  • @EnableAutoConfiguration
  • @ComponentScan

@SpringBootApplication by default, searches the package where it is present, as well as all the sub-packages. If a bean is present in a package other than the base package or its sub-packages, it will not be found. If we want Spring to find beans defined in other packages, we need to use the @ComponentScan annotation and provide the path of the package where we want Spring to look for the beans.

@PostConstruct

When Spring creates a bean, the first thing it does, is to autowire the dependencies. If the developer wants to perform a task after the dependencies have been populated, it can be done by calling a method annotated with the @PostConstruct annotation. A method with this annotation works like the init method. The @PostConstruct annotation tells Spring to call the method for us once the object has been created. The method can have any name and its return type is always void. After the bean is created, we can initialize the contents of the bean, load data, establish a database connection, or connect to a web server. The post construct method is only called after all the dependencies have been populated.

The logger messages give an insight into the sequence of events after the container is initialized. In order to create the RecommenderImplementation bean, the ContentBasedFilter bean is needed. The constructor of the ContentBasedFilter class is called. After the constructor method, the PostConstruct method is called. When the bean has been created, it is injected into the RecommenderImplementation bean as can be seen from the logger output of the setter method. After the dependency has been injected into the RecommenderImplementation bean, its PostConstruct method is called. Now the bean is ready for use and is returned by the getBean() method after which the bean name is printed.

Screenshot 2023-07-06 at 4 17 10 PM

@PreDestroy

The callback method that is executed just before the bean is destroyed is annotated using @PreDestroy. The method having this annotation is called when the bean is in the process of being removed from the container. All cleanup stuff can be performed in this method.

Bean Lifecycle

Lifecycle of prototype beans

Spring manages the entire lifecycle of singleton beans but it does not completely manage the lifecycle of prototype beans. This is because there might be a large number of prototype instances and the container can become overwhelmed keeping track of them.

The Spring container creates the prototype beans and hands them over when requested. Thereafter, it is the responsibility of the application to destroy the bean and free up any resources that it has acquired.

Contexts and Dependency Injection (CDI)

It is an interface that standardizes dependency injection for Java EE. It defines different annotations for dependency injection like @Named, @Inject, @Scope, @Singleton, etc. Different CDI implementation frameworks provide support and functionality for these annotations.

Stereotype Annotations

Beans can be declared using the @Bean annotation in a configuration class or by using the @Controller, @Service, and @Repository annotations.

The web or UI layer interacts with the client program, the service layer provides an abstraction between the web and data access layer as well as taking care of the business logic, and the data layer interacts with a database or an external interface. @Component is a generic annotation. It can be used in any layer, if the developer is unsure about where the bean belongs. The other three annotations, @Controller, @Service, and @Repository, are specific to layers.

The advantage of having annotations specific to every layer instead of the generic @Component is in Aspect Oriented Programming (AOP). We can identify the annotations and add functionality to specific annotations. Similarly, we can classify components in different categories and apply a specific logic to each category. For example, if we want to log everything that is coming from the business layer, we can identify objects with the @Service annotation using AOP and log all the content.

Springboot

Spring Boot is an opinionated framework built on top of the Spring framework, designed to simplify and accelerate the development of Spring applications.

Spring boot enables robust creation of applications. It provides features like servers, metrics, health checks, etc. Spring Boot allows for integration with many different servers, but by itself, it is neither an application server nor a web server. Auto configuration is a great feature of Spring Boot whereby it provides all the required dependencies to start a particular project. For example, starter web automatically configures everything needed for a web application. Similarly, starter JPA automatically configures basic JPA along with Hibernate.

Actuator

Spring Boot Actuator is a feature that provides monitoring features for the application during development and after deployment. It provides metadata about the application like the beans configured, how autoconfiguration has worked, how many times a specific service is called, how many times a specific service has failed, etc.

Screenshot 2023-07-06 at 5 43 25 PM

Aspect Oriented Programming

Aspect Oriented Programming (AOP) is the best approach for implementing cross-cutting concerns. Applications are divided into layers like web, business, data, etc. Each layer works independently. There are some concerns that are common across layers. These include security, logging, transaction management, auditing, error handling, performance tracking, etc.

Aspect

An aspect is a Java class that implements cross-cutting concerns. The @Aspect annotation is used to define a class as an aspect. An aspect is a combination of the kinds of methods to intercept and what to do after intercepting them. Aspects can define functionality for any concern like logging, performance management, or transaction management that cuts across multiple application layers.

Pointcut

Pointcuts are expressions that determine which method calls will be intercepted. These expressions determine whether an advice needs to be executed or not.

Advice

The tasks performed after intercepting a method call are called advices. It is the logic of the methods in a class marked with @Aspect. Advices are basically the methods that get executed when a method calls meets a pointcut.

Joinpoint

All method calls that are intercepted are joinpoints. It is a point in the program execution where an aspect can be plugged in.

Weaving

The process of implementing AOP around method calls is called weaving. Weaving links an aspect with objects in the application to create an advised object.

Defining an Aspect

When we intercept method calls, we have the option to perform tasks before the method is executed as well as afterwards. To define an aspect for a cross-cutting concern, we will perform the following steps:

  • Define aspect class.
  • Write methods containing the advice to be executed when method calls are intercepted.
  • Write pointcut expressions for intercepting method calls.

Aspect

Suppose we want to intercept method calls to check if the user has access before the method gets executed. Access check is a cross-cutting concern and instead of implementing it in every method, we can write it as an aspect.

We will create a class called AccessCheckAspect and place it in the aspect package. To establish that this is a configuration class, we will use the @Configuration annotation. We will also add the @Aspect annotation to establish that this class is related to AOP.

@Aspect
@Configuration
public class AccessCheckAspect {
}

###Advice The next step is to define a method that contains the logic of the steps that need to be carried out when a method call gets intercepted. We will create a method called userAccess and print a message as follows:

@Aspect
@Configuration
public class AccessCheckAspect {
    private Logger logger = LoggerFactory.getLogger(this.getClass());

    public void userAccess(JoinPoint joinPoint) {
        logger.info("Intercepted method call");
    }
}

Pointcut expression

User access needs to be checked before a method gets executed. We need the @Before annotation on our method. It ensures that the advice is run before the method is executed.

Joinpoint

To find out which method calls have been intercepted, we will use a join point as an argument to the method.

@Before("execution(* io.datajek.springaop.movierecommenderaop.business.*.*(..))")
public void userAccess(JoinPoint joinPoint) {
    logger.info("Intercepted call before execution: {}", joinPoint);
} 

Spring MVC

web.xml file

web.xml is the starting point for any web application. This is where Tomcat, or any other Java EE implementation server, starts looking for servlets

Creating a Servlet

A servlet is a Java class which can take in a request and return a response. The input to the servlet is a request and the output is a response. In a web application, we are talking about HTTP requests and HTTP responses. Servlet handles requests at a lower level than a controller.

  • We will create a servlet class in src/main/java and call it PlayerServlet. A servlet class extends the HttpServlet class.
  • The next step is to define a URL that will be used to access the servlet. We will assign /player.do to PlayerServlet. This can be done using the @WebServlet annotation.
  • Our servlet class will handle HTTP requests and respond with an HTTP response. The HttpServlet class has several methods to handle requests.
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(urlPatterns = "/player.do")
public class PlayerServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) 
                                                            throws IOException {
        PrintWriter out = response.getWriter();
        out.println("<html>");
        out.println("<head>" +
                 "<title>Player DB</title>" +
                 "</head>");
        out.println("<body>" +
                 "<H2>Welcome to the Tennis Players database!</H2>" +
                 "</body>");
        out.println("</html>");
    }
}

web.xml

<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
	version="3.0">
	<display-name>Tennis Player DB</display-name>
	<welcome-file-list>
		<welcome-file>player.do</welcome-file>
	</welcome-file-list> 
</web-app>

Writing HTML in Java is not good practice. We have to use the println method for every line of HTML code. A better approach is to use Java Server Pages (JSP) to write HTML content to the browser. A JSP is also compiled as a servlet so there is no performance gain in using JSPs. Rather, it is ease to use and able to send dynamic content to the browser.

The client sends a request (http://localhost:8080/player.do) to the web server (Tomcat). The web server maps the request to a servlet (PlayerServlet) and retrieves a page from the files (welcome.jsp). This page is sent as a response to the client. The browser interprets the response and displays the web page.

Spring MVC Architecture

Spring MVC request flow

In a nutshell, a request coming from the client is handled by the Spring MVC front controller which delegates the request to another controller. The controller creates a model and based on the user request, populates the model. Then it returns the model to the front controller. Now, the front controller passes this model to the view template which takes the data and renders the response to the client.

MVC architecture has a front controller that manages all the other controllers. The developer creates the controllers for the application and Spring MVC provides the front controller. The job of the front controller is to handle all requests coming from the client. The web.xml file, which is the entry point of a web application, contains the servlet mapping of the front controller such that all requests are forwarded to it. It is the job of the front controller to call another controller based on the request that it receives.

Screenshot 2023-07-07 at 5 29 08 PM

Compare this with the Java Servlet model, where web.xml maps each incoming request to a servlet and the servlet sends a response back to the client.

Screenshot 2023-07-07 at 5 29 43 PM

Dispatcher servlet

The front controller is called the DispatcherServlet. In order to know which controller to call, the dispatcher servlet needs a configuration file which contains information about where the controllers are placed. The @Controller annotation is used on all controllers and they are placed in the same package.

A request from the client goes to the web.xml as usual. In MVC architecture, web.xml forwards it to the dispatcher servlet. The dispatcher servlet checks its configuration file to find out which controller to invoke.

After the controller is executed, it sends two things back to the dispatcher servlet; the data or result (model) and the name of the page (view) to show to the client. The dispatcher servlet calls the view resolver to find the appropriate page, populates the page with the results and shows it to the client.

Screenshot 2023-07-07 at 5 31 42 PM

Spring MVC request flow

All incoming requests to a Spring MVC application are handled by the front controller called the DispatcherServlet. This front controller is part of the Spring JAR files and the developer is not required to implement it.

Screenshot 2023-07-07 at 5 50 50 PM

  1. Client sends a request to the application which is received by web.xml.
  2. web.xml forwards all requests to the dispatcher servlet.
  3. Dispatcher servlet checks its config file, player-servlet.xml, for controllers.
  4. Based on the controller mappings, “/” is mapped to the welcome method in the TennisController.
  5. The controller method returns a String response.
  6. Since the welcome method of the controller does not have the @ResponseBody annotation, the dispatcher servlet treats the return value as a view name and forwards it to the view resolver configured in player-servlet.xml file.
  7. The view resolver resolves the String main-menu to /WEB-INF/views/main-menu.jsp and returns the view/JSP to the dispatcher servlet.
  8. Dispatcher servlet renders the view in the browser.

The @RequestParam annotation is used to bind form data to a method parameter.

The @ModelAttribute is an annotation in Spring MVC that binds a method parameter or method return value to a named model attribute, exposed to a web view.

Screenshot 2023-07-07 at 9 54 20 PM

Data Validation

Data validation includes checking if the required fields are not left blank, numbers are within a given range, and data is entered in the correct format. The Standard Bean Validation API is the preferred approach for validation in Spring applications.

  • @NotNull checks if a required field is left blank.
  • @Size checks that the input matches a given number of characters or digits.
  • @Min and @Max validate that a number is within a given range.
  • @Past and @Future apply to date fields to check if the date entered is before or after the current date.
  • Regular expressions can be validated using the @Pattern annotation.
  • We can validate a model object by using the @Valid annotation in the controller class. When the user clicks the Submit button, the processForm method is executed. The @Valid annotation makes sure that the data entered by the user passes the validation rules.
    • If the result object does not have any errors, then the user can proceed to the player-confirmation page. The hasErrors() method, used in the code below, returns a Boolean value.
public static String processForm(@Valid @ModelAttribute("athlete") Athlete myAthlete, 
                                 BindingResult result) {
    if (result.hasErrors()) 
        return "add-player-form";
    else
        return "player-confirmation";
}

Create custom annotation

https://www.educative.io/module/page/Y6GKZ1ipY4VA9DQQG/10370001/5079044300734464/5692205131366400#Creating-custom-annotation

Interview Questions

  • What design patterns are used in Spring framework?
  • What is Inversion of Control (IoC)?
    • Suppose, class A is dependent on class B. In case of tight coupling, class A is responsible for creating an object of class B. In case of loose coupling, the framework takes the responsibility of creating and populating the dependency. The control of creating dependency shifts from the class to the framework. This is called Inversion of Control (IoC).
  • What is dependency injection?
    • Dependency injection is a concept which states that the developer should not create objects manually in the code but specify how the objects should be created. The IoC container reads this information and instantiates the object with the required dependencies. Dependency injection is the process of finding a bean to be autowired.
  • How is dependency injection related to inversion of control?
    • Inversion of control (IoC) is a general concept which can be expressed in different ways. Dependency injection is an example of IoC.
    • IoC concept is that the control of creating and wiring the dependencies shifts from the developer to the framework. Dependency injection is the process by which the framework identifies the dependencies of an object, finds a match, and wires the dependency in the object.
  • What are the types of dependency injection?
    • Field injection
    • Setter injection
    • Constructor injection
  • What is constructor injection?
    • In constructor injection, the IoC container creates the object by calling a constructor with a number of arguments where each argument represents a dependency on another class.
  • How does setter injection work?
    • Setter injection works by calling setter methods to set the property values. Spring container creates the object by calling the no-argument constructor and then calls setter methods to populate the dependencies.
    • The documentation for older versions of Spring suggested that constructor injection be used for all mandatory dependencies while setter injection for optional dependencies. However the @Required annotation on a setter method can be used to make it a mandatory dependency.

Beans

  • How are beans created?#
    • Spring framework creates beans in an order. When Spring framework encounters a bean definition in XML file or through an annotation, it checks if the class is dependent on any other class. Suppose class A has a dependency on class B. In this case, Spring will create the object of class B. Once the dependency has been created, the bean for class A can be created by injecting the bean of class B in class A.
  • What are the different scopes of a bean?
    • Singleton. Only one instance of the bean per IoC container is created.
    • Prototype. A new instance of the bean is created every time.
    • Session. One bean is created for every Http session.
    • Request. One bean is created per Http request.
    • Application. One bean is created per ServletContext.
    • Websocket. One bean is created per WebSocket.
  • Is Singleton scope in Spring same as the Singleton design pattern?
    • According to the Singleton design pattern, there can be one bean per Java class. In Spring, singleton scope means one bean per bean id per Spring container (ApplicationContext).
  • Explain prototype bean scope.
    • Prototype scope means that every time the developer asks for an instance of the bean, the Spring container will create a new instance and return it. This is different from the singleton scope, where only one instance of the bean is created and the Spring container returns the reference of the same instance whenever it receives a request for the bean.

Annotations

  • What is the purpose of @Component annotation?
    • @Component annotation is used to define a bean. Spring container scans the package (and its subpackages) specified in the component-scan tag. It will register all classes marked with the @Component annotation as beans.
  • Why is @Primary annotation used?
    • When two beans of the same type qualify to be autowired, then @Primary annotation is used to break the tie. Suppose there are two implementations of the Engine interface, CombustionEngine and ElectricEngine. The class Vehicle has a dependency on Engine interface. If both implementations have the @Component annotation then a compiler error will occur stating that more than one bean of the same type was found. In this case, we can guide Spring to use either CombustionEngine or ElectricEngine as the primary choice by using the @Primary annotation.
  • Why is @Qualifier annotation used?
    • If more than one bean of the same type exists, we can choose the bean to be autowired using the @Qualifier annotation. The bean having this annotation qualifies to be autowired.
  • Which annotations takes precedence: @Primary or @Qualifier?
    • When both the @Primary and @Qualifer annotations are present, then @Qualifier takes precedence. @Primary defines a default value and bean marked with this annotation will be used unless otherwise indicated. @Qualifier annotation is specific and is used when a particular bean is needed.

Configuration and Component Scan

  • What is component scan?
    • Component scan is the process in which Spring searches for beans. Spring needs to know the location (package) to search for beans. Using the @Component annotation and its sub-classes in which case Spring searches all the packages and sub-packages containing these annotation.
  • How does autowiring internally work?
    • Spring calls the setter method for the property when autowiring mode is byName and byType.
    • When autowiring mode is constructor and the class defines multiple constructors, then Spring will call the constructor with the most number of parameters.
  • Why do we need a no-arg constructor?
    • When we do not define a constructor for our class, the compiler defines a default one for us. But when we declare a parameterized constructor, the compiler does not create the default one. If we are creating an object without passing any arguments, it will need the default no-arg constructor. If it does not exist in the code, we need to explicitly define a no-arg constructor.
  • What is Spring Actuator?
    • Spring Actuator provides data about the application that can be used for performance analysis as well as debugging. The data provided by Actuator includes, among many other things, the health of the application, beans created, controller mappings, and memory used etc. The Actuator endpoints are secured using Spring Security.

Sprint MVC

  • What is the flow of request in the MVC architecture?
    • The dispatcher servlet is the front controller which receives all requests from the client. It has a mapping of all controllers and maps the incoming request to the appropriate controller.
    • The controller executes the request and returns a model and view name to the dispatcher servlet. The model contains the results.
    • The dispatcher servlet uses the view resolver to resolve the name of the view and populates it with results from the model and displays it to the client as a web page.
  • Front Controller Pattern
    • Front Controller Pattern is a design pattern in which request handling is centralized. All client requests go to the front controller which contains a mapping of all controllers/servlets. The front controller maps the client request to the relevant controller/servlet, receives the results back, and renders the view to the client.
    • In Spring DispatcherServlet is the front controller. It receives all the requests from the client and forwards them to the appropriate controller.
  • Describe the function of the DispatcherServlet.
    • The DispatcherServlet is at the heart of Spring MVC. It is the front controller which handles all the HTTP requests and responses.
    • The dispatcher servlet uses a configuration file containing information of all controllers and the URL mappings to forward an incoming request to the correct controller. It gets a model object and view back from the controller. The dispatcher servlet then forwards the view name to the view resolver and renders the response back to the client.
  • How is the Dispatcher servlet configured?
    • Spring provides its own implementation of the ServletContainerInitializer interface. We can use the class AbstractAnnotationConfigDispatcherServletInitializer and provide implementation of the getServletConfigClasses and getServletMappings methods to configure the dispatcher servlet.
  • What is a controller?
    • A controller is a class that handles user requests. It is annotated with the @Controller annotation.
    • A controller class contains the business logic of the application. Based on the client request, a controller populates the model which is shown to the user as a view.
  • What is the difference between @Controller and @RestController annotations?
    • Web applications and REST APIs differ in their return types with the former returning a view comprising of HTML, CSS and JavaScript while the later returning JSON or XML data.
    • The @Controller annotation populates the model map and returns a view name that is sent to the view resolver. The @RestController annotation returns an object which is written to HTTP response as JSON or XML.
    • The @RestController annotation is a combination of @Controller and @ResponseBody annotations. To return JSON or XML in a web application, we need to use the @ResponseBody annotation explicitly with the @Controller annotation.
  • What is an ambiguous mapping error?
    • When Spring finds more than one controller methods having the same URL mapping, HTTP request method, parameters, headers and media type, it throws the ambiguous mapping error because it cannot choose which controller method to map the incoming request to. Changing anything from the above mentioned list to differentiate the controller methods will resolve this error.
  • What is the function of @ResponseBody annotation?
    • The value returned by a controller method is resolved to a view name. However, if we want to write directly to the response body, we use the @ResponseBody annotation to tell Spring that instead of resolving the return value as a view name, it should be displayed to the client as a String.

AOP

  • What is AOP and how does it relate to OOP?
    • AOP stands for Aspect Oriented Programming. It divides the application logic into parts called concerns. AOP is similar to OOP in terms of modularity. It differs from OOP in the way modularity is defined. In OOP modularity is achieved by using classes whereas in AOP modularity is achieved using aspects that are applied to different class methods. Since aspects or concerns apply to the whole application, their processing should be centralized.
  • What is a cross cutting concern in AOP?
    • A cross cutting concern is something that affects the whole application. Instead of handling it separately in every layer, it is handled in a centralized manner. Examples of cross cutting concerns are security, logging, transaction management, and error handling etc.

Spring JDBC

Spring JDBC makes talking to databases easy by eliminating the need for establishing a connection, handling expectations, and closing connections. Spring provides a template class called JdbcTemplate to interact with databases which offers a wide array of methods to perform storage and retrieval of data. The JdbcTemplate class hides all the boilerplate code for connection management and error handling whereby the developer can focus on the SQL query.

  1. create JDBC starter project (edit POM)
  2. Setup H2 database (config in application.properties)

Steps required to interact with the database in JDBC.

  • The first step is establishing a connection.
  • The second step is creating a prepared statement or query.
  • The third step is to execute the query.
  • The fourth step is looping through the result set to get the objects.
  • The fifth and final step is to close the connection.

Spring JDBC: The connection part is automatically taken care of and the data source is automatically configured. Likewise, the connection is automatically closed.

Screenshot 2023-07-23 at 3 45 30 AM

Defining Player bean

We need to define a class Player with the same fields. The rows in the Player table will map to this class.

public class Player{
    private int id;
    private String name;
    private String nationality;
    private Date birthDate;
    private int titles;
    //. . .
}

Next, we will create two constructors (with arguments and no-argument), getters and setters, as well as a ToString method for the fields. The no-arg constructor is a requirement of the BeanPropertyRowMapper. The Player class is a bean and the data coming from the Player table in H2 will be mapped to this class.

Creating DAO class

We will create a new class PlayerDao to interact with the database. Since this class belongs to the data layer, we will use the @Repository annotation instead of the generic @Component annotation.

@Repository
public class PlayerDao {
	@Autowired
	JdbcTemplate jdbcTemplate;

	public List<Player> getAllPlayers() {
	    String sql = "SELECT * FROM PLAYER";
	    return jdbcTemplate.query(sql, new BeanPropertyRowMapper<Player>(Player.class));
	}
}

more: insert, update, delete, ddl

Custom RowMapper

The BeanPropertyRowMapper can be used to map the results of the query to our bean. If the database table has a different structure or column names, we need to define our custom mapping.

We can define our own row mapper by implementing the RowMapper interface and providing the bean onto which the rows will be mapped. The custom row mapper, PlayerMapper is created as an inner class because it will only be used inside JdbcPlayerDao.

@Repository
public class PlayerDao {
    //...
    private static final class PlayerMapper implements RowMapper<Player> {
    @Override
	public Player mapRow(ResultSet resultSet, int rowNum) throws SQLException {
	    Player player = new Player();
	    player.setId(resultSet.getInt("id"));
	    player.setName(resultSet.getString("name"));
	    player.setNationality(resultSet.getString("nationality"));
	    player.setBirthDate(resultSet.getTime("birth_date"));
	    player.setTitles(resultSet.getInt("titles"));
	    return player; 
	}
    }
}

To use PlayerMapper, we can simply pass it in any method instead of the BeanPropertyRowMapper.

public List<Player> getPlayerByNationality(String nationality) {
    String sql = "SELECT * FROM PLAYER WHERE NATIONALITY = ?";
    return jdbcTemplate.query(sql, new PlayerMapper(), new Object[] {nationality});
}

Spring JPA

How JPA works

JDBC requires the developer to write the queries, map values to the query, pass a set of parameters to execute the query, and map rows of the result set to a bean. For simple queries, this task is manageable, but in large applications with hundreds of tables, the queries become complex.

JPA challenges the notion of writing queries and mapping the data back. It creates entities that are Java objects which map to a row in a database table. JPA creates a schema based on the entities and defines relationships between entities. The Object-Relational Mapping (ORM) layer maps the objects to a database table.

Using JPA, we can map a Java class or bean to a table. The members of the class map columns in the table. When this mapping is defined, JPA can write queries on its own. It takes the responsibility of creating and executing queries for CRUD operations. This is due to the fact that the operations performed on a database are identical and can be generalized. The types of objects change based on the database schema but the operations remain the same.

Dependency

<dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

@Entity

We need to tell JPA that the objects of this class need to be mapped to a table in a database. JPA will create a table with the same name as the class and create columns for all the members of the class. Every instance of the Player class will become a row in the Player table. We will use the @Entity annotation to map this class to the Player table.

@Entity
@Table(name="Player")
Public class Player {

}

@Id and @GeneratedValue

Every table in a relational database has a primary key. In our case, the Id attribute uniquely identifies each object. The @Id annotation is used to indicate the primary key. We can also let JPA generate the primary key value when we insert rows. The @GeneratedValue annotation will automatically generate Id values.

@Entity
public class Player {
    @Id
    @GeneratedValue
    private int id;
    private String name;
    private String nationality;
    private Date birthDate;
    private int titles;
    // ...
}

@Column

Another annotation provided by the JPA API is @Column annotation, which is used to define column mappings. @Column annotation mentions the name of the column that matches an attribute of the class.

@Column(name="nationality")
private String nationality;

JPA schema creation

The Spring Boot autoconfiguration triggers a schema update and creates a table by the same name as the class marked with the @Entity annotation. When using JPA, we do not need to create a table. We will comment out the table creation query in schema.sql as it is not needed anymore.

@Repository annotation

We will create a PlayerRepository class to manage the Player entity and to store and retrieve data. We can mark this class with the @Repository annotation.

@Repository
public class PlayerRepository {

}

Enabling transaction management

Database queries contain multiple steps. We will also enable transaction management to allow all steps in a query to succeed. In case of an error or runtime exception, all steps will be rolled back. Transactions are implemented at the business layer. Spring provides all the boilerplate code to start, commit, and roll back a transaction, which can also be integrated with JPA’s transaction management. This is enabled using the @Transactional annotation on a method or a class.

@Repository
@Transactional
public class PlayerRepository{

}   

Using this annotation on the PlayerRepository class, all the methods will be executed in a transactional context. So if we have INSERT and UPDATE in a single method, something called an EntityManager will keep track of both of them. If one of them fails, the whole operation will be rolled back.

EntityManager and @PersistenceContext annotation

A JPA EntityManager manages connection to a database as well as to database operations. EntityManager is associated with a PersistenceContext. All operations that are performed in a specific session are stored inside the PersistenceContext. EntityManager is the interface to the Persistence Context. All operations on the entity go through the EntityManager. We will declare an EntityManager object in our class and mark it with the @PersistenceContext annotation.

public class PlayerRepository{
    @PersistenceContext
    EntityManager entityManager;
    //...
}

EntityManager provides a number of methods that perform SELECT, INSERT, UPDATE, and DELETE queries.

@NamedQuery

To create a named query, we will use the @NamedQuery annotation on the Player class. This annotation requires two parameters: the name of the query and the query itself. When using JPA, we will write the query in JPQL instead of SQL. JPQL uses entities in place of tables. Since we want to return a list of Player objects, the query will be "SELECT p FROM Player p".

@Entity
@NamedQuery(name="get_all_players", query="select p from Player p")
public class Player {
    //...
}

Spring random

JdbcTemplate.queryForObject: This method in Spring's JDBC template is used to query the database for a single row and map the row to a single object. It is commonly used when you expect the query to return exactly one row and want to map that row to a Java object. The method throws an EmptyResultDataAccessException if no rows are found and IncorrectResultSizeDataAccessException if more than one row is found.

JdbcTemplate is a central class in the Spring framework's JDBC (Java Database Connectivity) abstraction layer, which simplifies the use of JDBC and helps to avoid common errors when interacting with a relational database. It handles the creation and release of resources, such as opening and closing connections to the database, executing SQL queries, and iterating over the ResultSet. This allows developers to focus on the logic of data access rather than dealing with the boilerplate code associated with database operations.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment