0% found this document useful (0 votes)
18 views12 pages

Unit 2

api
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
18 views12 pages

Unit 2

api
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 12

Unit-2:

1.Introduction to Spring AOP

Aspect-Oriented Programming (AOP) is a programming paradigm that aims to address cross-cutting


concerns, such as logging, security, and transaction management, in a modular and loosely coupled
manner.

Key Advantages of Spring AOP

1. Separation of Concerns: Keeps cross-cutting concerns separate from business logic.

2. Dynamic Application: Cross-cutting concerns are applied during runtime based on


configurations.

3. Modularity: Allows for easy updates to cross-cutting concerns without affecting core logic.

4. Aspect as a Unit: Unlike OOP, where classes are the primary unit of modularity, AOP uses
Aspects as modular units.

Core Concepts in Spring AOP

Term Description

A modular unit of cross-cutting concerns, implemented as a class with the @Aspect


Aspect
annotation.

A specific point in the application, like method execution, where cross-cutting concerns
Joinpoint
can be applied.

Advice Code that implements cross-cutting concerns, executed at specific join points.

An expression that determines where advice should be applied (e.g., before or after
Pointcut
specific methods).

Types of Advice

Type Execution Point

Before Executes before the join point.

After Executes after the join point, regardless of the outcome (like a finally block).

AfterReturning Executes after the join point returns successfully.

AfterThrowing Executes if the join point throws an exception.

Around Wraps the join point with logic before and after its execution.

Key Annotations in Spring AOP

1. @Aspect
Declares a class as an aspect.
2. @Before, @After, @AfterReturning, @AfterThrowing, @Around
Specify when advice should run relative to the join point.

3. @Pointcut
Declares reusable pointcut expressions.

Pointcut Syntax

 General Form:

php

Copy code

execution(<modifiers>? <return-type> <fully-qualified-class-name>.<method-


name>(<parameters>?))

 Explanation:

o execution: Indicates the method execution join point.

o <modifiers>: Access specifier (e.g., public). Optional.

o <return-type>: The return type of the method (* for any return type).

o <fully-qualified-class-name>: The class containing the target methods. Optional.

o <method-name>: Name of the method to match (* for any method).

o <parameters>: Method parameters (.. matches any number of parameters).

2. Implementing AOP Advices in Spring

AOP (Aspect-Oriented Programming) allows you to define cross-cutting concerns (like logging,
security, transaction management) separately from the core business logic. Below are examples of
various types of AOP advices that can be used in Spring to log actions or handle exceptions, typically
used in services like fetchCustomer() from a service class such as CustomerServiceImpl.

1. Before Advice

Before advice is executed before the actual method is called.

Example of Before Advice:

java

Copy code

@Aspect

@Component

public class LoggingAspect {

@Before("execution(* com.infy.service.CustomerServiceImpl.fetchCustomer(..))")
public void logBeforeAdvice(JoinPoint joinPoint) {

logger.info("In Before Advice, Joinpoint signature :{}", joinPoint.getSignature());

long time = System.currentTimeMillis();

String date = DateFormat.getDateTimeInstance().format(time);

logger.info("Report generated at time: {}", date);

Explanation:

 @Before: Executes before the fetchCustomer() method in the CustomerServiceImpl class.

 joinPoint.getSignature(): Provides information about the method being executed.

 Logging the current time: A timestamp for when the report is generated.

2. After Advice

After advice is executed after the method execution, regardless of whether it throws an exception or
not. It is useful for cleanup tasks like closing resources.

Example of After Advice:

java

Copy code

@Aspect

@Component

public class LoggingAspect {

@After("execution(* com.infy.service.CustomerServiceImpl.fetchCustomer(..))")

public void logAfterAdvice(JoinPoint joinPoint) {

logger.info("In After Advice, Joinpoint signature :{}", joinPoint.getSignature());

long time = System.currentTimeMillis();

String date = DateFormat.getDateTimeInstance().format(time);

logger.info("Report generated at time: {}", date);

Explanation:
 @After: This advice is executed after fetchCustomer() finishes execution, even if an exception
occurs.

 It logs the time of the report generation after the method has executed.

3. After Returning Advice

This advice is executed only when the method successfully completes without throwing an
exception. It is typically used to log results or process return values.

Example of After Returning Advice:

java

Copy code

@Aspect

@Component

public class LoggingAspect {

@AfterReturning(pointcut = "execution(*
com.infy.service.CustomerServiceImpl.fetchCustomer(..))")

public void logDetails(JoinPoint joinPoint) {

logger.info("In AfterReturning Advice, Joinpoint signature :{}", joinPoint.getSignature());

Accessing the Return Value:

You can access the value returned by the method using the returning attribute.

java

Copy code

@Aspect

@Component

public class LoggingAspect {

@AfterReturning(pointcut = "execution(*
com.infy.service.CustomerServiceImpl.fetchCustomer(..))", returning = "result")

public void logDetails(JoinPoint joinPoint, String result) {

logger.info("In AfterReturning Advice with return value, Joinpoint signature :{}",


joinPoint.getSignature());
logger.info(result);

Explanation:

 @AfterReturning: Executes after the method returns successfully.

 returning = "result": The result variable holds the value returned by fetchCustomer().

4. After Throwing Advice

This advice is executed only if the target method throws an exception. It's useful for logging or
handling exceptions that occur in the method.

Example of After Throwing Advice:

java

Copy code

@Aspect

@Component

public class LoggingAspect {

@AfterThrowing("execution(* com.infy.service.CustomerServiceImpl.fetchCustomer(..))")

public void logAfterThrowingAdvice(JoinPoint joinPoint) {

logger.info("In AfterThrowing Advice, Joinpoint signature :{}", joinPoint.getSignature());

Accessing the Exception:

You can access the exception thrown by the target method.

java

Copy code

@Aspect

@Component

public class LoggingAspect {

@AfterThrowing(pointcut = "execution(*
com.infy.service.CustomerServiceImpl.fetchCustomer(..))", throwing = "exception")
public void logAfterThrowingAdvice(JoinPoint joinPoint, Exception exception) {

logger.info("In AfterThrowing Advice, Joinpoint signature :{}", joinPoint.getSignature());

logger.info("Exception message: {}", exception.getMessage());

Explanation:

 @AfterThrowing: Executes when an exception is thrown from fetchCustomer().

 throwing = "exception": The exception variable contains the exception thrown by the
method.

Summary of AOP Advice Types:

Advice Type When It Executes

Before Advice Executed before the target method call.

Executed after the target method finishes, regardless of the outcome (success or
After Advice
exception).

After Executed after the method successfully returns, used for logging return values or
Returning post-processing.

After Throwing Executed if the target method throws an exception, useful for error logging.

These advices provide a powerful way to modularize the handling of cross-cutting concerns such as
logging, exception handling, and resource management, all while keeping the core business logic
intact.

3. Best Practices for Spring Boot Application Development

Adopting best practices in the design and development of Spring Boot applications ensures better
maintainability, performance, security, and testability. Here are the key best practices for quality and
security in Spring Boot development.

1. Use Spring Initializr for Project Setup

The simplest and most effective way to create a Spring Boot project is by using Spring Initializr. It
provides a user-friendly interface to generate a production-ready application. This can be directly
imported into IDEs like Spring Tool Suite (STS) or Eclipse for further development.

 URL: Spring Initializr

Advantages:

 Quick setup with the required dependencies.


 Allows customization of project metadata like the group, artifact, Java version, etc.

2. Follow Standard Project Structure

A well-structured project helps in maintaining a clean, organized, and scalable application. There are
two popular approaches for project structuring in Spring Boot applications:

First Approach:

 Group related classes (controllers, services, etc.) by the domain. For example:

o com.infy.customer for all customer-related classes.

o com.infy.order for order-related classes.

Second Approach:

 Group classes based on the layer of the application. For example:

o com.infy.service for service classes.

o com.infy.controller for controller classes.

o com.infy.repository for repository classes.

Avoid Using the Default Package:

 Do not place classes in the default package, as this can cause issues with Spring Boot's
@ComponentScan and @SpringBootApplication annotations. Use proper package naming
conventions like com.infy.service or com.infy.controller.

3. Use Constructor Injection for Mandatory Dependencies

In Spring, there are multiple ways to inject dependencies into beans, but constructor injection is
recommended for mandatory dependencies because:

 It makes the dependencies immutable.

 It improves testability and ensures that all required dependencies are provided at the time of
object creation.

 It avoids the problem of uninitialized fields that can occur with field injection.

Example:

java

Copy code

@Autowired

public CustomerService(CustomerRepository customerRepository) {

this.customerRepository = customerRepository;

}
 Setter Injection can be used for optional dependencies, but constructor injection is generally
the best practice for required dependencies.

4. Avoid Using Stereotype Annotations in Domain Classes

Domain classes (i.e., entities) should not use Spring's stereotype annotations like @Component,
@Service, or @Repository as it can lead to unnecessary bean creation. These annotations are
typically reserved for business logic layers and services, not for domain models.

 Example (incorrect):

java

Copy code

@Component

public class Employee {

// Domain class with unnecessary Spring annotations

 Instead, let Spring manage beans in the application layer (@Service, @Controller, etc.).

5. Use Scoped Beans Wisely

When defining beans, it's essential to choose the correct scope for the bean:

 Singleton Scope (default): Use for stateless beans where the state doesn’t change between
requests.

 Prototype Scope: Use for stateful beans that need a new instance each time they are
requested.

6. Avoid Unnecessary Bean Scanning

By default, Spring scans all classes in the package where the application starts
(@SpringBootApplication). However, if you only need to scan a specific package, specify that package
explicitly to avoid unnecessary bean scanning.

Example:

java

Copy code

@Configuration

@ComponentScan("com.infosys.service") // Only scan the service package

public class AppConfig {


// Configuration code

7. Autowire Dependencies Using Constructor Injection

To make the application more maintainable and testable, use the @Autowired annotation on
constructors instead of fields or setter methods. Constructor injection is preferred because it ensures
that dependencies are immutable and provides better testability.

java

Copy code

@Autowired

public MyService(MyRepository myRepository) {

this.myRepository = myRepository;

8. Define Pointcuts in a Common Class for AOP

For cleaner and more maintainable Aspect-Oriented Programming (AOP), store all your Pointcut
expressions in a common class. This allows easier maintenance and reusability of pointcuts in
multiple aspects.

Example:

java

Copy code

public class CommonPointConfig {

@Pointcut("execution(* com.infy.service.CustomerServiceImpl.fetchCustomer(..))")

public void logBeforeAdvice() {}

Then use the pointcut in your aspect:

java

Copy code

@Around("com.infy.service.CustomerServiceImpl.fetchCustomer.aspect.CommonPointConfig.logBefo
reAdvice()")

public void logAround(ProceedingJoinPoint joinPoint) {

// Logic

}
9. Proper Error Handling with Exception Handling Advice

In any application, effective error handling is crucial for robustness. Spring allows handling exceptions
globally using @ControllerAdvice and @ExceptionHandler. It's a good practice to centralize exception
handling in a dedicated class.

Example:

java

Copy code

@ControllerAdvice

public class GlobalExceptionHandler {

@ExceptionHandler(ResourceNotFoundException.class)

public ResponseEntity<ErrorDetails>
handleResourceNotFoundException(ResourceNotFoundException ex) {

ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getMessage(), "Resource not


found");

return new ResponseEntity<>(errorDetails, HttpStatus.NOT_FOUND);

10. Security Best Practices

Security is a critical aspect of any application, and Spring Boot provides numerous security features.
Follow these best practices to ensure your Spring Boot application is secure:

 Always use HTTPS for communication.

 Validate user inputs to avoid SQL injection and other vulnerabilities.

 Use Spring Security for authentication and authorization.

 Avoid exposing sensitive information in the application logs or exceptions.

 Use CSRF protection in web applications, even if it's a stateless API, with tokens like JWT for
better security.

11. Testing Best Practices

Testing is an essential part of any Spring Boot application. Use the following best practices for
effective testing:
 Use unit tests for individual methods or components (using @Test).

 Use integration tests to test the interaction between components and the database.

 Mock external services and API calls with tools like Mockito.

 Follow the Arrange-Act-Assert pattern in tests to keep them clean and understandable.

Example of Unit Test:

java

Copy code

@RunWith(SpringRunner.class)

@SpringBootTest

public class CustomerServiceTest {

@Autowired

private CustomerService customerService;

@MockBean

private CustomerRepository customerRepository;

@Test

public void testFetchCustomer() {

Customer mockCustomer = new Customer("John", "Doe");

Mockito.when(customerRepository.findById(1L)).thenReturn(Optional.of(mockCustomer));

Customer customer = customerService.fetchCustomer(1L);

assertNotNull(customer);

assertEquals("John", customer.getFirstName());

12. Choose Constructor-based DI for Mandatory Dependencies

As a best practice, always use constructor-based dependency injection for mandatory dependencies
and setter-based injection for optional ones. This helps in ensuring that objects are fully initialized
when created, making the code more predictable and easier to test.
Conclusion

By following these best practices, you can build clean, secure, scalable, and maintainable Spring
Boot applications. These practices help in better application design, easier testing, improved
performance, and enhanced security. They are essential for developing high-quality applications that
can be efficiently maintained and extended over time.

You might also like