SpringBoot整合aspectj实现面向切面编程(即AOP)
- 作者: 五速梦信息网
- 时间: 2026年04月04日 13:27
前言
“面向切面编程”,这样的名字并不是非常容易理解,且容易产生一些误导。但在实际业务中,AOP有着广泛的用途,比如日志记录,性能统计,安全控制,事务处理,异常处理等等。
举些栗子
统计每个接口的耗时
记录操作人,还要记录入参出参
统一处理这些异常
…
难点分析&解决方案上面的场景都是真实存在的需求,但是如果不能统一处理的话,基本都是一改一大片,除了对业务代码有很强的侵入性,而且难以保证不出问题。
所以为了解决这种需求,AspectJ框架应运而生。不过SpringBoot官方也推出了 Spring AOP, 具体对比我就不赘述了,详细对比可以参https://www.jianshu.com/p/872d3dbdc2ca

1、引入依赖
<dependency>
<groupId>org.aspectj</groupId><br/>
<artifactId>aspectjweaver</artifactId><br/>
<version>1.9.5</version><br/>
</dependency>
2、创建切面类并加上@Component注解
这一步相当于把切面类的管理权交给了Spring容器,让Spring容器负责该对象的创建与销毁,我们负责使用就行。
3、指定@Pointcut,可以是方法也可以是注解
这里说一下Pointcut execution规则
execution(public * (..))execution( set(..))execution( com.example.springbootaop.UserService.(..))execution( com.example.springbootaop..(..))execution(* com.example.springbootaop.service...(..))execution(* com.example.springbootaop..UserService.*(..))“)
4、五大通知注解
尝试一下
1、配置文件
SpringBoot项目pom.xml
<?xml version=”1.0“ encoding=”UTF-8“?>
<project xmlns=”http://maven.apache.org/POM/4.0.0" xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><br/>
<modelVersion>4.0.0</modelVersion><br/>
<parent><br/>
<groupId>org.springframework.boot</groupId><br/>
<artifactId>spring-boot-starter-parent</artifactId><br/>
<version>2.7.1</version><br/>
<relativePath/> <!-- lookup parent from repository --><br/>
</parent><br/>
<groupId>com.example</groupId><br/>
<artifactId>SpringBoot-aop</artifactId><br/>
<version>0.0.1-SNAPSHOT</version><br/>
<name>SpringBoot-aop</name><br/>
<description>Demo project for Spring Boot</description><br/>
<properties><br/>
<java.version>1.8</java.version><br/>
</properties><br/>
<dependencies><br/>
<dependency><br/>
<groupId>org.springframework.boot</groupId><br/>
<artifactId>spring-boot-starter-web</artifactId><br/>
</dependency>
<dependency>
<groupId>org.aspectj</groupId><br/>
<artifactId>aspectjweaver</artifactId><br/>
<version>1.9.5</version><br/>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId><br/>
<artifactId>spring-boot-starter-test</artifactId><br/>
<scope>test</scope><br/>
</dependency><br/>
</dependencies>
<build>
<plugins><br/>
<plugin><br/>
<groupId>org.springframework.boot</groupId><br/>
<artifactId>spring-boot-maven-plugin</artifactId><br/>
</plugin><br/>
</plugins><br/>
</build>
</project>
2、项目代码
项目结构

SpringBootAopApplication.java
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringBootAopApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootAopApplication.class, args);<br/>
}
}
TestController.java
import com.example.springbootaop.log.Log;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;
@RestController
@RequestMapping(”/aop“)
public class TestController {
@GetMapping(”/a“)
@Log(desc = "接口a的描述")<br/>
public String a() {<br/>
return "我是接口a";<br/>
}
@GetMapping(”/b“)
@Log(desc = "接口b的描述")<br/>
public String b(String param1) {<br/>
System.out.println("打印参数:" + param1);<br/>
return "我是接口b";<br/>
}
@PostMapping(”/c“)
@Log(desc = "接口c的描述")<br/>
public String c(Map<String, String> stringMap) {<br/>
System.out.println("打印参数:" + stringMap);<br/>
return "我是接口c";<br/>
}<br/>
}
ControllerLogAspect.java
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
@Aspect
@Component
@Order(1)
public class ControllerLogAspect {
private static final Logger LOG = LoggerFactory.getLogger(ControllerLogAspect.class);
@Pointcut(”execution(* com.example.springbootaop.controller...(..))“)
private void controllerMethod() {<br/>
}
@Around(”controllerMethod()“)
public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {<br/>
RequestAttributes ra = RequestContextHolder.getRequestAttributes();<br/>
ServletRequestAttributes sra = (ServletRequestAttributes) ra;<br/>
HttpServletRequest request = sra.getRequest();<br/>
// 获取请求相关信息<br/>
String url = request.getRequestURL().toString();<br/>
String method = request.getMethod();<br/>
String uri = request.getRequestURI();<br/>
String params = request.getQueryString();<br/>
LOG.info("url:[{}];method:[{}];uri:[{}];params:[{}]", url, method, uri, params);<br/>
return joinPoint.proceed();<br/>
}<br/>
}
Log.java
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Log {
String desc() default ”“;
}
LogAspect.java
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
@Aspect
@Component
@Order(2)
public class LogAspect {
private static final Logger LOG = LoggerFactory.getLogger(LogAspect.class);
@Pointcut(”@annotation(com.example.springbootaop.log.Log)“)
private void pointCut() {
}
@Around(”pointCut()“)
public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {<br/>
MethodSignature signature = (MethodSignature) joinPoint.getSignature();<br/>
Method method = signature.getMethod();<br/>
//获取注解<br/>
Log logAnnotation = method.getAnnotation(Log.class);<br/>
LOG.info("当期方法的注解为:[{}]", logAnnotation.desc());<br/>
return joinPoint.proceed();<br/>
}<br/>
}
3、项目总结
上面的项目使用了两种切面
(1)ControllerLogAspect
ControllerLogAspectcom.example.springbootaop.controller
(2)Log注解 + LogAspect
这种方式扫描的不再是某个包,而是某个注解,Pointcut代码如下
@Pointcut(”@annotation(com.example.springbootaop.log.Log)“)
private void pointCut() {<br/>
}<br/>
配合注解一起使用,更加清晰且灵活,每一个方法都可以配置自己的信息,这种一般会用在日志记录、异常处理等场景。
在idea中如果是切面的话,出现如下图标,点击就可以看到所有被切入的方法:

相关文章
-
springboot整合mybatis源码分析
springboot整合mybatis源码分析
- 互联网
- 2026年04月04日
-
SpringBoot整合Shiro+MD5+Salt+Redis实现认证和动态权限管理丨前后端分离(下)
SpringBoot整合Shiro+MD5+Salt+Redis实现认证和动态权限管理丨前后端分离(下)
- 互联网
- 2026年04月04日
-
springboot之websocket,STOMP协议
springboot之websocket,STOMP协议
- 互联网
- 2026年04月04日
-
springboot实现服务器端消息推送(websocket + sockjs + stomp)
springboot实现服务器端消息推送(websocket + sockjs + stomp)
- 互联网
- 2026年04月04日
-
springboot启动后异步启动一个程序
springboot启动后异步启动一个程序
- 互联网
- 2026年04月04日
-
Springboot接口字符串判空
Springboot接口字符串判空
- 互联网
- 2026年04月04日






