本文目录导读:

在Java中,实现环绕通知最主流的做法是使用Spring AOP的@Around注解,环绕通知可以在目标方法执行前后添加自定义逻辑,甚至可以完全控制目标方法的执行。
基础环境搭建
确保项目引入Spring AOP依赖:
Maven依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
启用AOP
在配置类上添加@EnableAspectJAutoProxy注解:
@Configuration
@EnableAspectJAutoProxy
public class AopConfig {
}
创建环绕通知
示例1:简单的性能监控切面
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 PerformanceAspect {
@Around("execution(* com.example.service.*.*(..))")
public Object monitorPerformance(ProceedingJoinPoint joinPoint) throws Throwable {
// 前置逻辑:记录开始时间
long startTime = System.currentTimeMillis();
System.out.println("开始执行方法: " + joinPoint.getSignature().getName());
try {
// 执行目标方法
Object result = joinPoint.proceed();
return result;
} finally {
// 后置逻辑:计算执行时间
long endTime = System.currentTimeMillis();
long duration = endTime - startTime;
System.out.println("方法 " + joinPoint.getSignature().getName() +
" 执行耗时: " + duration + "ms");
}
}
}
示例2:日志记录切面
@Aspect
@Component
public class LoggingAspect {
@Around("execution(* com.example.controller.*.*(..))")
public Object logMethodCall(ProceedingJoinPoint joinPoint) throws Throwable {
// 获取方法参数
String methodName = joinPoint.getSignature().getName();
Object[] args = joinPoint.getArgs();
System.out.println("调用方法: " + methodName);
System.out.println("参数: " + Arrays.toString(args));
Object result = null;
try {
// 执行目标方法
result = joinPoint.proceed();
System.out.println("方法返回: " + result);
return result;
} catch (Exception e) {
System.out.println("方法异常: " + e.getMessage());
throw e;
} finally {
System.out.println("方法执行完毕: " + methodName);
}
}
}
示例3:权限验证切面
@Aspect
@Component
public class SecurityAspect {
@Around("@annotation(com.example.annotation.RequireAuth)")
public Object checkAuthentication(ProceedingJoinPoint joinPoint) throws Throwable {
// 获取当前用户信息(假设从ThreadLocal获取)
User currentUser = SecurityContext.getCurrentUser();
if (currentUser == null) {
throw new SecurityException("用户未登录");
}
// 获取注解信息
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
RequireAuth annotation = signature.getMethod().getAnnotation(RequireAuth.class);
String requiredRole = annotation.role();
// 检查权限
if (!currentUser.hasRole(requiredRole)) {
throw new SecurityException("权限不足");
}
// 权限验证通过,执行目标方法
return joinPoint.proceed();
}
}
目标业务类
@Service
public class UserService {
public User findUserById(Long id) {
System.out.println("查询用户ID: " + id);
// 模拟耗时操作
try {
Thread.sleep(100);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
return new User(id, "张三");
}
}
@RestController
@RequestMapping("/api/users")
public class UserController {
@GetMapping("/{id}")
@RequireAuth(role = "ADMIN")
public User getUser(@PathVariable Long id) {
return new User(id, "张三");
}
}
自定义注解
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 RequireAuth {
String role() default "USER";
}
测试类
@SpringBootTest
@RunWith(SpringRunner.class)
public class AopTest {
@Autowired
private UserService userService;
@Test
public void testAroundAdvice() {
userService.findUserById(1L);
}
}
关键知识点
ProceedingJoinPoint 常用方法
| 方法 | 说明 |
|---|---|
proceed() |
执行目标方法 |
proceed(Object[] args) |
用指定的参数执行目标方法 |
getArgs() |
获取方法参数数组 |
getSignature() |
获取方法签名 |
getTarget() |
获取目标对象 |
getThis() |
获取代理对象 |
环绕通知执行流程
@Around("pointcut")
public Object around(ProceedingJoinPoint pjp) {
// 1. 前置处理
// ...
try {
// 2. 执行目标方法
Object result = pjp.proceed();
// 3. 后置处理(方法正常返回)
// ...
return result;
} catch (Exception e) {
// 4. 异常处理
// ...
throw e;
}
}
注意事项
- 必须调用proceed():如果环绕通知不调用
proceed(),目标方法将不会执行 - 返回结果处理:环绕通知必须返回目标方法的执行结果,否则调用方将收到null
- 异常传播:异常应该继续向上抛出,除非你想改变异常类型
- 线程安全:确保环绕通知中的共享资源访问是线程安全的
环绕通知是最强大的通知类型,因为它可以完全控制目标方法的执行过程,适合用于事务管理、日志记录、性能监控、安全控制等场景。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播