1. @Before Pre-Notice
1.1 Basic Instructions
- Execute before the target method is executed
- Cannot prevent the target method from being executed (unless an exception is thrown)
- You can obtain parameter information of the target method
1.2 Implementation example
@Aspect @Component public class SecurityAspect { @Before("@annotation(requiresAuth)") public void checkAuth(JoinPoint joinPoint, RequiresAuth requiresAuth) { // Get current user information ServletRequestAttributes attributes = (ServletRequestAttributes) (); HttpServletRequest request = (); String token = ("Authorization"); // Verify token if (!(token)) { throw new UnauthorizedException("Invalid authentication token"); } // Check permissions String requiredRole = (); if (!hasRole(token, requiredRole)) { throw new ForbiddenException("Insufficient permissions"); } } }
1.3 Typical application scenarios
- Permission verification
- Parameter verification
- Logging
- Transaction start tag
- Cache preprocessing
1.4 Get parameters
1.4.1 Basic parameter acquisition
@Before("execution(* .*.*(..))") public void beforeAdvice(JoinPoint joinPoint) { // Get method parameters Object[] args = (); // Get the method signature MethodSignature signature = (MethodSignature) (); String methodName = (); // Get the parameter name String[] parameterNames = (); // Get parameter type Class<?>[] parameterTypes = (); // Print parameter information for (int i = 0; i < ; i++) { ("Parameter {} ({}) = {}", parameterNames[i], parameterTypes[i].getSimpleName(), args[i]); } }
1.4.2 Get annotation parameters
@Before("@annotation(logParams)") public void beforeWithAnnotation(JoinPoint joinPoint, LogParams logParams) { // Get the annotation attributes directly String description = (); boolean logResult = (); // Get method parameters Object[] args = (); //Configure logs according to annotation if (()) { (args) .forEach(arg -> ("Parameter value: {}", arg)); } }
2. @After Post notification
2.1 Basic instructions
- Execute after the target method is executed (regardless of whether the exception is thrown or not)
- Cannot access the return value of the target method
- Mainly used for cleaning up resources or similar finishing work
2.2 Implementation example
@Aspect @Component public class ResourceCleanupAspect { @After("execution(* .*(..))") public void cleanup(JoinPoint joinPoint) { try { // Clean up temporary files String methodName = ().getName(); ("Cleaning up resources after method: {}", methodName); cleanupTempFiles(); // Release other resources releaseResources(); } catch (Exception e) { ("Cleanup failed", e); } } private void cleanupTempFiles() { // Specific implementation of cleaning temporary files } private void releaseResources() { // Specific implementation of freeing resources } }
2.3 Typical application scenarios
- Resource Cleanup
- Connection closes
- Counter update
- Logging
- Performance monitoring end mark
2.4 Parameter acquisition
@After("execution(* .*.*(..)) && args(id,name,..)") public void afterAdvice(JoinPoint joinPoint, Long id, String name) { // Use parameters directly ("Method executed with ID: {} and name: {}", id, name); // Get target information Class<?> targetClass = ().getClass(); // Get agent information Class<?> proxyClass = ().getClass(); }
3. @AfterReturning Return to Notification
3.1 Basic description
- Execute after the target method is successfully executed
- The return value of the target method can be accessed
- You can modify the return value (through the wrapper class)
3.2 Implementation example
@Aspect @Component public class ResponseHandlerAspect { @AfterReturning( pointcut = "execution(* .*.*(..))", returning = "result" ) public void handleResponse(JoinPoint joinPoint, Object result) { if (result instanceof List) { // Desensitize the set type results List<?> list = (List<?>) result; for (Object item : list) { if (item instanceof UserDTO) { UserDTO user = (UserDTO) item; (maskPhoneNumber(())); (maskEmail(())); } } } } private String maskPhoneNumber(String phone) { // Mobile phone number desensitization logic return ("(\\d{3})\\d{4}(\\d{4})", "$1****$2"); } private String maskEmail(String email) { // Email Desensitization Logic return ("(\\w{3})\\w+(@\\w+\\.\\w+)", "$1***$2"); } }
3.3 Typical application scenarios
- Modify the return value (such as data desensitization)
- Statistical method success rate
- Cache results
- Format result
- Data collection packaging
4. @AfterThrowing Exception Notification
4.1 Basic description
- Execute when the target method throws an exception
- You can access the thrown exception information
- Exception conversion or processing can be performed
4.2 Implementation example
@Aspect @Component public class ExceptionHandlerAspect { @AfterThrowing( pointcut = "execution(* .*.*(..))", throwing = "ex" ) public void handleException(JoinPoint joinPoint, Exception ex) { String methodName = ().getName(); String className = ().getClass().getSimpleName(); // Record detailed error information ("Exception in {}.{}: {}", className, methodName, ()); // Send an alarm if (ex instanceof DataAccessException) { (className, methodName, ex); } // Exception classification statistics (className, methodName, ().getSimpleName()); // If necessary, you can convert the exception type if (ex instanceof SQLException) { throw new DatabaseException("Database operation failed", ex); } } }
4.3 Typical application scenarios
- Exception logging
- Exception conversion
- Alarm notification
- Failed to try again
- Error statistics
5. @Around Surround Notification
5.1 Basic Instructions
- The most powerful notification type, with complete control over the execution of the target method
- Custom behavior can be added before and after method execution
- Can modify the parameters and return values of the method
- Can decide whether to execute the target method
5.2 Implementation Example
@Aspect @Component public class CacheAspect { @Autowired private CacheManager cacheManager; @Around("@annotation(cacheable)") public Object handleCache(ProceedingJoinPoint joinPoint, Cacheable cacheable) throws Throwable { // Build cache key String key = buildCacheKey(joinPoint, cacheable); // Try to get from cache Object cachedValue = (key); if (cachedValue != null) { ("Cache hit for key: {}", key); return cachedValue; } // Execute the target method long startTime = (); Object result = null; try { result = (); // Record execution time long executionTime = () - startTime; ("Method execution time: {}ms", executionTime); // If the execution time exceeds the threshold, send an alarm if (executionTime > 1000) { (joinPoint, executionTime); } } catch (Exception e) { // Exception handling ("Method execution failed", e); throw e; } // Put the result into cache if (result != null) { (key, result, ()); } return result; } private String buildCacheKey(ProceedingJoinPoint joinPoint, Cacheable cacheable) { // Cache key construction logic StringBuilder key = new StringBuilder(); (().getDeclaringTypeName()) .append(".") .append(().getName()); Object[] args = (); if (args != null && > 0) { (":"); for (Object arg : args) { (arg != null ? () : "null").append(","); } } return (); } }
5.3 Typical application scenarios
- Method Cache
- Performance monitoring
- Transaction processing
- Retry mechanism
- Concurrent control
- Current limiting processing
@Aspect @Component public class RateLimiterAspect { private final RateLimiter rateLimiter = (100.0); // 100 requests per second @Around("@annotation(rateLimited)") public Object limitRate(ProceedingJoinPoint joinPoint, RateLimited rateLimited) throws Throwable { if (!(100, )) { throw new TooManyRequestsException("Requests are too frequent, please try again later"); } return (); } }
6. Best Practices
-
Select the right notification type
- If only pre-processing is required, use @Before
- If you need to access the return value, use @AfterReturning
- If you need to handle exceptions, use @AfterThrowing
- If you need to have full control over the execution of the method, use @Around
-
Performance considerations
- Avoid time-consuming operations in notifications
- Use cache reasonably
- Pay attention to the performance impact of exception handling
-
Code Organization
- Each section focuses on a single responsibility
- Keep notification methods simple
- Multiplexing common point-cut expressions
-
Exception handling
- Exception handling should be done in notifications
- Don't swallow the abnormalities
- Convert exception types appropriately
This is the end of this article about the detailed explanation and practical Spring AOP notification type. For more related Spring AOP notification type content, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!