Spring AOP注解实现详解

举报
鱼弦 发表于 2025/05/29 08:41:41 2025/05/29
【摘要】 Spring AOP注解实现详解一、核心注解概述Spring AOP通过以下核心注解实现面向切面编程:@Aspect:声明切面类@Pointcut:定义切入点表达式通知注解:@Before:前置通知@After:后置通知@AfterReturning:返回后通知@AfterThrowing:异常通知@Around:环绕通知二、基础配置启用AOP注解支持@Configuration@Enabl...

Spring AOP注解实现详解

一、核心注解概述

Spring AOP通过以下核心注解实现面向切面编程:
@Aspect:声明切面类

@Pointcut:定义切入点表达式

通知注解:

@Before:前置通知

@After:后置通知

@AfterReturning:返回后通知

@AfterThrowing:异常通知

@Around:环绕通知

二、基础配置
启用AOP注解支持

@Configuration
@EnableAspectJAutoProxy // 启用AOP注解支持
public class AppConfig {

定义切面类

@Aspect
@Component
public class LoggingAspect {

// 定义切入点表达式
@Pointcut("execution( com.example.service..*(..))")
private void serviceLayer() {}

三、通知类型详解
前置通知(@Before)

@Before(“serviceLayer()”)
public void beforeAdvice(JoinPoint joinPoint) {
System.out.println("方法调用前: " + joinPoint.getSignature().getName());
System.out.println("参数: " + Arrays.toString(joinPoint.getArgs()));

后置通知(@After)

@After(“serviceLayer()”)
public void afterAdvice(JoinPoint joinPoint) {
System.out.println("方法执行完成: " + joinPoint.getSignature().getName());

返回后通知(@AfterReturning)

@AfterReturning(
pointcut = “serviceLayer()”,
returning = “result”
)
public void afterReturningAdvice(JoinPoint joinPoint, Object result) {
System.out.println("方法返回: " + joinPoint.getSignature().getName());
System.out.println("返回值: " + result);

异常通知(@AfterThrowing)

@AfterThrowing(
pointcut = “serviceLayer()”,
throwing = “ex”
)
public void afterThrowingAdvice(JoinPoint joinPoint, Exception ex) {
System.out.println("方法抛出异常: " + joinPoint.getSignature().getName());
System.out.println("异常信息: " + ex.getMessage());

环绕通知(@Around)

@Around(“serviceLayer()”)
public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("环绕前: " + joinPoint.getSignature().getName());

try {
    Object result = joinPoint.proceed(); // 执行目标方法
    System.out.println("环绕后: 方法正常返回");
    return result;

catch (Exception e) {

    System.out.println("环绕后: 方法抛出异常");
    throw e;

}

四、切入点表达式
常用表达式语法

表达式 说明

execution( com.example.service…(…)) service包下所有类的所有方法
execution(public (…)) 所有public方法
execution( set(…)) 所有以set开头的方法
within(com.example.service.
) service包下的所有类
@annotation(com.example.Loggable) 带有@Loggable注解的方法

组合表达式

@Pointcut(“execution( com.example.service…(…)) && !execution( com.example.service.UserService.*(…))”)
public void serviceLayerExceptUserService() {}

五、高级特性
引入(Introduction)

@Aspect
@Component
public class UsageTrackingAspect {

@DeclareParents(
    value = "com.example.service.*+",
    defaultImpl = DefaultUsageTracked.class
)
public static UsageTracked mixin;

public interface UsageTracked {

void incrementUseCount();

public class DefaultUsageTracked implements UsageTracked {

private int useCount = 0;

@Override
public void incrementUseCount() {
    useCount++;

}

参数绑定

@Before(“serviceLayer() && args(name)”)
public void beforeAdviceWithParam(JoinPoint joinPoint, String name) {
System.out.println("方法参数name: " + name);

六、性能优化建议
减少切入点表达式复杂度:复杂表达式会增加匹配时间

合理选择通知类型:优先使用@Around,减少代理链长度

避免在切面中执行耗时操作:会影响所有被代理方法

使用@Order指定切面顺序:避免不必要的执行顺序调整

七、常见问题解决
切面不生效

可能原因:
未添加@EnableAspectJAutoProxy

切面类未被Spring管理(缺少@Component等注解)

切入点表达式不匹配目标方法
自调用问题

Spring AOP基于代理实现,类内部方法调用不会触发切面逻辑。解决方案:

// 通过AopContext获取当前代理对象
((UserService)AopContext.currentProxy()).internalMethod();

八、实际应用案例
日志记录切面

@Aspect
@Component
public class LoggingAspect {

private final Logger logger = LoggerFactory.getLogger(this.getClass());

@Pointcut("within(@org.springframework.web.bind.annotation.RestController *)")
public void controllerLayer() {}

@Around("controllerLayer()")
public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
    logger.info("Enter: {}.{}()", 
        joinPoint.getSignature().getDeclaringTypeName(),
        joinPoint.getSignature().getName());
    
    try {
        Object result = joinPoint.proceed();
        logger.info("Exit: {}.{}() with result = {}", 
            joinPoint.getSignature().getDeclaringTypeName(),
            joinPoint.getSignature().getName(), 
            result);
        return result;

catch (Exception e) {

        logger.error("Exception in {}.{}() with cause = {}", 
            joinPoint.getSignature().getDeclaringTypeName(),
            joinPoint.getSignature().getName(),
            e.getCause() != null ? e.getCause() : "NULL");
        throw e;

}

性能监控切面

@Aspect
@Component
public class PerformanceAspect {

@Around("@annotation(com.example.MonitorPerformance)")
public Object monitorPerformance(ProceedingJoinPoint joinPoint) throws Throwable {
    long startTime = System.currentTimeMillis();
    
    try {
        return joinPoint.proceed();

finally {

        long executionTime = System.currentTimeMillis() - startTime;
        System.out.println(joinPoint.getSignature() + " executed in " + executionTime + "ms");

}

通过以上注解实现,Spring AOP可以优雅地实现横切关注点,保持业务代码的整洁性。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。