SoFunction
Updated on 2025-05-21

SpringBoot uses AOP to log requests

Introduction

AOP (Aspect-Oriented Programming) is a programming paradigm that aims to improve the modularity of code by separating cross-cutting concerns.

Cross-cutting concerns refer to functions that span multiple modules, such as logging, transaction management, security checking, etc.

AOP makes the code easier to maintain and scale by separating these features from the core business logic.

Core concept

1. Aspect:

  • The section is a modular implementation of cross-cutting concerns. It contains notifications (Advice) and point-cut.
  • For example, the logging function can be used as a section.

2. Join Point:

  • A connection point is a specific point during the execution of the program, such as method calls, exception throwing, etc.
  • AOP can insert additional behavior at these points.

3. Notification (Advice):

  • Notification is an action performed by a section at a specific connection point. Common notification types include:
  • Before Advice: Execute before the target method is executed.
  • After Advice: Execute after the target method is executed.
  • Return notification (After Returning Advice): Execute after the target method returns successfully.
  • Exception notification (After Throwing Advice): Executes after the target method throws an exception.
  • Around Advice: Executes both before and after the target method is executed, and you can control whether the target method is executed.

4. Pointcut:

  • The tangent is used to define which connection points trigger notifications. It matches the join points by expression or rules.
  • For example, match all methods starting with save.

5. Introduction:

  • Introducing allows adding new methods or attributes to existing classes without modifying the class's source code.

6. Target object:

The target object is an object notified by one or more sections, usually a class of core business logic.

7. Proxy:

  • The AOP framework implements the facet function by creating proxy objects.
  • The proxy object inserts notifications before and after the target object's method call.

How to implement AOP

1. Static proxy:

Generate proxy classes at compile time, such as compile-time weaving of AspectJ.

2. Dynamic proxy:

Generate proxy classes at runtime, such as the JDK dynamic proxy or CGLIB used by Spring AOP.

AOP application scenarios

1. Logging:

Logs are logged before and after method calls, without manually adding log code in each method.

2. Transaction management:

Manage the opening, commit or rollback of transactions before and after method execution.

3. Safety inspection:

Check user permissions before method invocation.

4. Performance monitoring:

Time is recorded before and after method execution, used for performance analysis.

5. Exception handling:

Execute specific processing logic when a method throws an exception.

Advantages of AOP

1. Modular:

Separate cross-cutting concerns from core business logic to make the code clearer and easier to maintain.

2. Code reuse:

Achieve common functions through sections to avoid duplicate code.

3. Flexibility:

Slices can be added or removed dynamically without modifying core business code.

Disadvantages of AOP

1. Learning curve:

For beginners, the concept and implementation of AOP may be difficult to understand.

2. Debugging difficulties:

Since the section logic is dynamically inserted, it may be difficult to track down problems during debugging.

3. Performance overhead:

Dynamic proxy and runtime weaving can bring some performance overhead.

AOP implementation framework

1、Spring AOP:

The Spring framework provides an AOP implementation based on dynamic proxying and is easy to integrate with Spring.

2、AspectJ:

Powerful AOP framework that supports compile-time weaving and run-time weaving.

3、JBoss AOP:

AOP implementation provided by JBoss supports complex facet logic.

Code combat

  • maven dependency
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="/POM/4.0.0" xmlns:xsi="http:///2001/XMLSchema-instance"
         xsi:schemaLocation="/POM/4.0.0 /xsd/maven-4.0.">
	<modelVersion>4.0.0</modelVersion>

	<artifactId>spring-boot-demo-log-aop</artifactId>
	<version>1.0.0-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>spring-boot-demo-log-aop</name>
	<description>Demo project for Spring Boot</description>

	<parent>
		<groupId></groupId>
		<artifactId>spring-boot-demo</artifactId>
		<version>1.0.0-SNAPSHOT</version>
	</parent>

	<properties>
		<>UTF-8</>
		<>UTF-8</>
		<>1.8</>
	</properties>

	<dependencies>
		<dependency>
			<groupId></groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId></groupId>
			<artifactId>spring-boot-starter-aop</artifactId>
		</dependency>

		<dependency>
			<groupId></groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>

		<dependency>
			<groupId></groupId>
			<artifactId>lombok</artifactId>
			<optional>true</optional>
		</dependency>

		<dependency>
			<groupId></groupId>
			<artifactId>hutool-all</artifactId>
		</dependency>

		<!-- Analysis UserAgent information -->
		<dependency>
			<groupId></groupId>
			<artifactId>UserAgentUtils</artifactId>
		</dependency>
	</dependencies>

	<build>
		<finalName>spring-boot-demo-log-aop</finalName>
		<plugins>
			<plugin>
				<groupId></groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>
@Aspect
@Component
@Slf4j
public class AopLog {
	private static final String START_TIME = "request-start";

	/**
	  * Point of entry
	  */
	@Pointcut("execution(public * .*Controller.*(..))")
	public void log() {

	}

	/**
	  * Pre-operation
	  *
	  * @param point entry point
	  */
	@Before("log()")
	public void beforeLog(JoinPoint point) {
		ServletRequestAttributes attributes = (ServletRequestAttributes) ();

		HttpServletRequest request = (attributes).getRequest();

		("【ask URL】:{}", ());
		("【ask IP】:{}", ());
		("【ask类名】:{},【ask方法名】:{}", ().getDeclaringTypeName(), ().getName());

		Map<String, String[]> parameterMap = ();
		("【ask参数】:{},", (parameterMap));
		Long start = ();
		(START_TIME, start);
	}

	/**
	  * Surround operation
	  *
	  * @param point entry point
	  * @return The original method returns the value
	  * @throws Throwable Exception information
	  */
	@Around("log()")
	public Object aroundLog(ProceedingJoinPoint point) throws Throwable {
		Object result = ();
		("【Return value】:{}", (result));
		return result;
	}

	/**
	  * Post-operation
	  */
	@AfterReturning("log()")
	public void afterReturning() {
		ServletRequestAttributes attributes = (ServletRequestAttributes) ();
		HttpServletRequest request = (attributes).getRequest();

		Long start = (Long) (START_TIME);
		Long end = ();
		("【ask耗时】:{}millisecond", end - start);

		String header = ("User-Agent");
		UserAgent userAgent = (header);
		("【Browser Type】:{},【operating system】:{},【originalUser-Agent】:{}", ().toString(), ().toString(), header);
	}
}
@RestController
public class TestController {

	/**
	  * Test method
	  *
	  * @param who Test parameters
	  * @return {@link Dict}
	  */
	@GetMapping("/test")
	public Dict test(String who) {
		return ().set("who", (who) ? "me" : who);
	}

}

Summarize

The above is personal experience. I hope you can give you a reference and I hope you can support me more.