Topic 5:- 5 concept of AOP and 5 types of Advices in AOP

image 2

Play Store Application link – Spring Framework in 9 steps – Apps on Google Play

Understanding AOP (Aspect-Oriented Programming) in Spring

Github project link (Xml based) – https://github.com/kuldeep101990/SpringAOPXml

Github project link (Annotation based) – https://github.com/kuldeep101990/SpringAOPAnnotation

1- Aspect

An Aspect is a class that defines common behaviors (advices) to be applied at specific points (join points) in your application. It can be configured via XML or using Spring’s AspectJ integration.

2- Join Point

A Join Point is a specific point in the execution of your application where an aspect can be applied. Spring primarily supports method execution as join points.

Example:

public class UserServiceImpl implements UserService {
    public void addUser(User user) {
        // Implementation code to add a user
    }
}
// Here, the execution of addUser() is a join point where an aspect can be applied.

3- Advice

Advice is the action taken at a join point. It can run before, after, or around method execution.

Example of Before Advice:

public class LoggingAspect {
    @Before("execution(* com.example.service.*.*(..))") // Match any method in service package
    public void logBefore(JoinPoint joinPoint) {
        System.out.println("Before " + joinPoint.getSignature().getName() + " method is called");
    }
}
// logBefore() logs a message before the matched method executes.

4- Target Object

The Target Object is the object being advised by aspects. In Spring, this is usually a proxy object.

Example:

@Configuration
@EnableAspectJAutoProxy // Enable AspectJ proxying
public class AppConfig {
    @Bean
    public LoggingAspect loggingAspect() {
        return new LoggingAspect();
    }
    @Bean
    public UserService userService() {
        return new UserServiceImpl(); // Target object
    }
}

5- Weaving

Weaving is the process of linking aspects with target objects to create advised proxy objects. This occurs at runtime in Spring.

Example of Weaving:

// Same AppConfig as before enables weaving of aspects with the UserService

Types of Advice

  1. Before Advice:
   @Before("execution(* com.example.UserService.addUser(..))")
   public void beforeAddUserAdvice() {
       System.out.println("Before adding a user...");
   }
  1. After Returning Advice:
   @AfterReturning("execution(* com.example.UserService.getUser(..))")
   public void afterGetUserAdvice() {
       System.out.println("After getting a user...");
   }
  1. After Throwing Advice:
   @AfterThrowing(value="execution(* com.example.UserService.deleteUser(..))", throwing="ex")
   public void afterDeleteUserAdvice(Throwable ex) {
       System.out.println("Exception during delete: " + ex.getMessage());
   }
  1. After Advice (Finally):
   @After("execution(* com.example.UserService.*(..))")
   public void afterUserServiceAdvice() {
       System.out.println("After UserService method call...");
   }
  1. Around Advice:
   @Around("execution(* com.example.UserService.getAllUsers(..))")
   public Object aroundGetAllUsersAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
       System.out.println("Before getting all users...");
       Object result = joinPoint.proceed(); // Proceed with the original method
       System.out.println("After getting all users...");
       return result; // Return the result
   }

Integrating AOP with Logging

Without IoC

public class SimpleSpellChecker implements SpellChecker {
    public void checkSpelling() {
        System.out.println("Inside checkSpelling method.");
        Logger.getLogger(SimpleSpellChecker.class.getName()).info("Starting checkSpelling...");
    }
}
public class TextEditor {
    private SpellChecker spellChecker;
    public TextEditor() {
        spellChecker = new SimpleSpellChecker(); // Manual instantiation
    }
    public void spellCheck() {
        spellChecker.checkSpelling();
        Logger.getLogger(TextEditor.class.getName()).info("Finished spellCheck...");
    }
}

With IoC

@Component
public class SimpleSpellChecker implements SpellChecker {
    @Override
    public void checkSpelling() {
        System.out.println("Inside checkSpelling method.");
    }
}
@Component
public class TextEditor {
    private SpellChecker spellChecker;
    @Autowired // Spring automatically injects the dependency
    public TextEditor(SpellChecker spellChecker) {
        this.spellChecker = spellChecker;
    }
    public void spellCheck() {
        spellChecker.checkSpelling();
    }
}
@Aspect
@Component
public class LoggingAspect {
    @Before("execution(* com.example.*.*(..))")
    public void logBefore(JoinPoint joinPoint) {
        System.out.println("Starting method execution: " + joinPoint.getSignature().getName());
    }
    @After("execution(* com.example.*.*(..))")
    public void logAfter(JoinPoint joinPoint) {
        System.out.println("Finishing method execution: " + joinPoint.getSignature().getName());
    }
}

Conclusion

Using AOP in Spring allows for modular and maintainable code by separating cross-cutting concerns like logging. This makes it easier to manage and apply behaviors across various components without changing their source code.

Other AOP Features

1- Caching

Use AOP to cache the results of expensive method calls.

@Aspect
@Component
public class CachingAspect {
    private Map<String, Object> cache = new HashMap<>();
    @Around("execution(* com.example.service.*.*(..))")
    public Object cacheResult(ProceedingJoinPoint joinPoint) throws Throwable {
        String key = joinPoint.getSignature().toString();
        if (cache.containsKey(key)) {
            return cache.get(key); // Return cached result
        }
        Object result = joinPoint.proceed(); // Proceed with method execution
        cache.put(key, result); // Cache the result
        return result;
    }
}

2- Transactions

Manage transactions without cluttering business logic.

@Aspect
@Component
public class TransactionAspect {
    @Around("execution(* com.example.service.*.*(..))")
    public Object manageTransaction(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("Transaction started.");
        try {
            Object result = joinPoint.proceed(); // Proceed with method execution
            System.out.println("Transaction committed.");
            return result;
        } catch (Exception e) {
            System.out.println("Transaction rolled back.");
            throw e; // Handle exception
        }
    }
}

3- Exception Handling

Centralize exception handling logic.

@Aspect
@Component
public class ExceptionHandlingAspect {
    @AfterThrowing(pointcut = "execution(* com.example.service.*.*(..))", throwing = "ex")
    public void handleException(Throwable ex) {
        System.out.println("Exception occurred: " + ex.getMessage());
        // Additional logging or handling logic here
    }
}

4- Performance Monitoring

Measure method execution times.

@Aspect
@Component
public class PerformanceMonitoringAspect {
    @Around("execution(* com.example.service.*.*(..))")
    public Object monitorPerformance(ProceedingJoinPoint joinPoint) throws Throwable {
        long start = System.currentTimeMillis();
        Object result = joinPoint.proceed(); // Proceed with method execution
        long duration = System.currentTimeMillis() - start;
        System.out.println("Execution time: " + duration + " ms");
        return result;
    }
}

5- Security

Apply security checks across methods.

@Aspect
@Component
public class SecurityAspect {
    @Before("execution(* com.example.service.*.*(..))")
    public void checkSecurity() {
        // Implement security checks here
        System.out.println("Security check passed.");
    }
}

6- Validation

Ensure input data validity.

@Aspect
@Component
public class ValidationAspect {
    @Before("execution(* com.example.service.*.*(..)) && args(input)")
    public void validateInput(String input) {
        if (input == null || input.isEmpty()) {
            throw new IllegalArgumentException("Input cannot be null or empty.");
        }
    }
}

These code snippets demonstrate how to implement common AOP features using Spring, promoting better code organization and separation of concerns.


Leave a Reply

Your email address will not be published. Required fields are marked *