Swiftorial Logo
Home
Swift Lessons
Tutorials
Learn More
Career
Resources

Advice Types in Spring AOP

Advice is the action taken by an aspect at a particular join point. Spring AOP provides several types of advice that can be applied to join points. This guide covers the key types of advice in Spring AOP, including their definitions and examples of how to use them.

Key Types of Advice in Spring AOP

  • Before Advice: Executed before the join point.
  • After Advice: Executed after the join point, regardless of the outcome.
  • After Returning Advice: Executed after the join point if it completes normally.
  • After Throwing Advice: Executed if the join point throws an exception.
  • Around Advice: Wraps the join point, allowing custom behavior before and after the join point.

Before Advice

Before advice is executed before the join point. It is defined using the @Before annotation.

Example: Before Advice

// LoggingAspect.java
package com.example.myapp.aspect;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class LoggingAspect {

    @Before("execution(* com.example.myapp.service.*.*(..))")
    public void logBeforeMethod() {
        System.out.println("A method is about to be executed.");
    }
}

After Advice

After advice is executed after the join point, regardless of the outcome. It is defined using the @After annotation.

Example: After Advice

// LoggingAspect.java
package com.example.myapp.aspect;

import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class LoggingAspect {

    @After("execution(* com.example.myapp.service.*.*(..))")
    public void logAfterMethod() {
        System.out.println("A method has been executed.");
    }
}

After Returning Advice

After returning advice is executed after the join point if it completes normally. It is defined using the @AfterReturning annotation.

Example: After Returning Advice

// LoggingAspect.java
package com.example.myapp.aspect;

import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class LoggingAspect {

    @AfterReturning(pointcut = "execution(* com.example.myapp.service.*.*(..))", returning = "result")
    public void logAfterReturning(Object result) {
        System.out.println("A method has returned: " + result);
    }
}

After Throwing Advice

After throwing advice is executed if the join point throws an exception. It is defined using the @AfterThrowing annotation.

Example: After Throwing Advice

// LoggingAspect.java
package com.example.myapp.aspect;

import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class LoggingAspect {

    @AfterThrowing(pointcut = "execution(* com.example.myapp.service.*.*(..))", throwing = "error")
    public void logAfterThrowing(Throwable error) {
        System.out.println("An exception has been thrown: " + error);
    }
}

Around Advice

Around advice wraps the join point, allowing custom behavior before and after the join point. It is defined using the @Around annotation.

Example: Around Advice

// LoggingAspect.java
package com.example.myapp.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class LoggingAspect {

    @Around("execution(* com.example.myapp.service.*.*(..))")
    public Object logAroundMethod(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("Before method: " + joinPoint.getSignature().getName());
        Object result = joinPoint.proceed();
        System.out.println("After method: " + joinPoint.getSignature().getName());
        return result;
    }
}

Using Advice in Your Application

Use the defined advice in your service layer to log method executions:

Example: UserService.java

// UserService.java
package com.example.myapp.service;

import com.example.myapp.model.User;
import com.example.myapp.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Optional;

@Service
public class UserService {

    @Autowired
    private UserRepository userRepository;

    @Transactional(readOnly = true)
    public List findAllUsers() {
        return userRepository.findAll();
    }

    @Transactional(readOnly = true)
    public Optional findUserById(Long id) {
        return userRepository.findById(id);
    }

    @Transactional
    public User saveUser(User user) {
        return userRepository.save(user);
    }

    @Transactional
    public void deleteUser(Long id) {
        userRepository.deleteById(id);
    }
}

Testing Spring AOP Advice

Test your Spring AOP advice setup to ensure it works as expected:

Example: UserServiceTests.java

// UserServiceTests.java
package com.example.myapp;

import com.example.myapp.model.User;
import com.example.myapp.repository.UserRepository;
import com.example.myapp.service.UserService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;

import java.util.Optional;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.when;

@SpringBootTest
public class UserServiceTests {

    @Autowired
    private UserService userService;

    @MockBean
    private UserRepository userRepository;

    @Test
    public void testFindUserById() {
        User user = new User();
        user.setId(1L);
        user.setUsername("testuser");
        user.setPassword("password");

        when(userRepository.findById(1L)).thenReturn(Optional.of(user));

        Optional foundUser = userService.findUserById(1L);
        assertThat(foundUser).isNotEmpty();
        assertThat(foundUser.get().getUsername()).isEqualTo("testuser");
    }
}

Key Points

  • Before Advice: Executed before the join point.
  • After Advice: Executed after the join point, regardless of the outcome.
  • After Returning Advice: Executed after the join point if it completes normally.
  • After Throwing Advice: Executed if the join point throws an exception.
  • Around Advice: Wraps the join point, allowing custom behavior before and after the join point.
  • Use the defined advice in your service layer to log method executions.
  • Test your Spring AOP advice setup to ensure it works as expected.

Conclusion

Advice is the action taken by an aspect at a particular join point. Spring AOP provides several types of advice that can be applied to join points, including before advice, after advice, after returning advice, after throwing advice, and around advice. By understanding and using these types of advice, you can effectively manage and modularize cross-cutting concerns in your Spring Boot application. Happy coding!