Spring Boot HandBook

    Declaring Advice

    Introduction:#

    Declaring Advice refers to the process of defining specific behaviors or actions (like logging, security checks, or transaction handling) that should occur at predefined points during the execution of a program. In Aspect-Oriented Programming (AOP), advice is declared within an aspect and is associated with certain join points (such as method executions, object instantiations, etc.) through pointcut expressions. When the specified join points are reached, the advice is executed as part of the aspect's cross-cutting concern.

    In simpler terms, declaring advice means specifying what should happen before, after, or around a method's execution in a modular and reusable way, without altering the actual business logic. This is achieved by creating an aspect and using annotations or XML configuration to indicate where and when the advice should be applied.

    Imagine you're a director of a play. The actors performing on stage represent your core business logic, the actual performance. The director oversees the play, ensuring certain things happen behind the scenes to ensure the show runs smoothly, like checking the lighting, controlling the sound, or ensuring the stage crew is ready.

    Now, in this analogy:

    • Advice is like the director's instructions to the crew, like telling them to adjust the lights just before a scene starts, or to ensure the sound is on at a specific time during the play.
    • Declaring Advice is like the director writing out a script that specifies when these backstage actions should occur, without interrupting the actors' performances.
    • The aspect would be the backstage operations, which are separate from the actors' performances but still crucial for the overall play to be successful.

    Different Advice Type#

    1. @Before Advice#

    • When it runs: Before the target method executes.
    • Use cases:
      • Logging method entry.
      • Validating method arguments before execution.
      • Performing some pre-processing logic.
    • Example:
    @Aspect @Component @Slf4j public class LoggingAspectV2 { @Before("allServiceMethodsPointCut()") //use that pointcut method public void beforeServiceMethodCalls(JoinPoint joinPoint) { log.info("Before advice method call, {}", joinPoint.getSignature()); } //explicit pointcut @Pointcut("execution(* com.codingshuttle.week1.week1.services.impl.*.*(..))") public void allServiceMethodsPointCut() { } }

    2. @After Advice#

    • When it runs: After the target method finishes executing, regardless of whether it completes normally or throws an exception.
    • Use cases:
      • Logging method completion.
      • Cleaning up resources after method execution (e.g., closing files, database connections).
    • Example:
    @Aspect @Component @Slf4j public class LoggingAspectV2 { @After("allServiceMethodsPointCut()") //use that pointcut method public void afterServiceMethodCalls(JoinPoint joinPoint, Object returnedObj) { log.info("After advice method call, {}", joinPoint.getSignature()); } //explicit pointcut @Pointcut("execution(* com.codingshuttle.week1.week1.services.impl.*.*(..))") public void allServiceMethodsPointCut() { } }

    3. @AfterReturning Advice#

    • When it runs: After a method successfully completes (without throwing an exception).
    • Use cases:
      • Logging return values.
      • Post-processing the returned value (e.g., formatting, additional calculations).
    • Example
    @Aspect @Component @Slf4j public class LoggingAspectV2 { @AfterReturning(value = "allServiceMethodsPointCut()") //use that pointcut method public void afterServiceMethodCalls(JoinPoint joinPoint, Object returnedObj) { log.info("After returning advice method call, {}", joinPoint.getSignature()); } //explicit pointcut @Pointcut("execution(* com.codingshuttle.week1.week1.services.impl.*.*(..))") public void allServiceMethodsPointCut() { } }

    4. @AfterThrowing Advice#

    • When it runs: After a method throws an exception.
    • Use cases:
      • Logging exceptions.
      • Handling specific exceptions and performing additional actions, such as notifying an administrator.
    • Example:
    @Aspect @Component @Slf4j public class LoggingAspectV2 { @AfterThrowing("allServiceMethodsPointCut()") public void afterServiceMethodCallsThrows(JoinPoint joinPoint) { log.info("After throwing advice method call, {}", joinPoint.getSignature()); } //explicit pointcut @Pointcut("execution(* com.codingshuttle.week1.week1.services.impl.*.*(..))") public void allServiceMethodsPointCut() { } }

    5. @Around Advice#

    • When it runs: Around the method execution. This advice gives you control before and after the method runs and even allows you to prevent the method from running or change its behavior.
    • Use cases:
      • Transaction management (commit or rollback depending on success/failure).
      • Performance monitoring (measuring execution time).
      • Modifying method return values or exceptions.
    • Example:
    @Aspect @Component @Slf4j public class LoggingAspectV2 { @Around("allServiceMethodsPointCut()") public Object logExecutionTime(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { Long startTime = System.currentTimeMillis(); Object returnedValue = proceedingJoinPoint.proceed(); Long endTime = System.currentTimeMillis(); Long diff = endTime-startTime; log.info("Time taken for {} is {}", proceedingJoinPoint.getSignature(), diff); return returnedValue; } //explicit pointcut @Pointcut("execution(* com.codingshuttle.week1.week1.services.impl.*.*(..))") public void allServiceMethodsPointCut() { } }

    Conclusion#

    This article explains the role of declaring advice in Aspect-Oriented Programming (AOP) within Spring Boot, emphasizing its ability to modularize cross-cutting concerns like logging and security. It covers various types of advice, including @Before, @After, @AfterReturning, @AfterThrowing, and @Around, and their impact on code maintainability and performance. Overall, AOP helps in creating cleaner, more modular applications.

    Last updated on Jan 14, 2025