[特殊字符] Spring AOP 注解方式详解
一、AOP 注解方式简介
学习了 Spring AOP 的 XML 配置方式,
需要写很多 <aop:aspect>、<aop:before> 标签来配置切面。
但在实际开发中,这样写太麻烦了!
Spring 提供了更简洁的方式 —— 使用注解来实现 AOP。
通过几个简单的注解,就能实现相同甚至更强大的功能。
二、AOP 注解方式的基本步骤
AOP 注解方式的实现步骤非常简单:
导入 AOP 相关依赖(和之前一样)
编写业务类(目标对象)
编写切面类,加上
@Aspect和各种通知注解在配置文件中开启注解代理
<aop:aspectj-autoproxy/>编写测试类进行验证
是不是比 XML 清爽多了?😎
三、准备工作
1️⃣ Maven 依赖
与上一章完全相同,只要确保包含了这几个核心包:
<!-- Spring AOP 相关 -->
<dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>5.0.2.RELEASE</version>
</dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.8.3</version>
</dependency>
四、业务层代码
我们先写一个普通的业务类——订单业务类。
OrderService.java
package com.qcbyjy.demo3;public interface OrderService {void save();
}
OrderServiceImpl.java
package com.qcbyjy.demo3;import org.springframework.stereotype.Service;@Service // 把该类交给IOC容器管理
public class OrderServiceImpl implements OrderService {@Overridepublic void save() {System.out.println("业务层:保存订单...");}
}
五、编写切面类(使用注解声明切面)
MyAnnoAspect.java
package com.qcbyjy.demo3;import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;@Component // 交给Spring容器管理
@Aspect // 声明这是一个切面类(相当于 <aop:aspect>)
public class MyAnnoAspect {/*** 通知方法*/@Before(value = "execution(public * com.qcbyjy.demo3.OrderServiceImpl.save(..))")public void log() {System.out.println("【AOP增强】方法执行前:记录日志...");}
}
📘 解释一下:
@Aspect:声明当前类是一个切面。@Before:声明一个前置通知。execution(...):切入点表达式,表示拦截OrderServiceImpl.save()方法。
六、Spring 配置文件开启 AOP 支持
在 applicationContext_demo3.xml 中,添加一行关键配置:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd"><!-- 扫描包 --><context:component-scan base-package="com.qcbyjy.demo3"/><!-- 开启AOP注解代理 --><aop:aspectj-autoproxy/>
</beans>
这句 <aop:aspectj-autoproxy/> 就是关键,相当于告诉 Spring:
“去扫描那些带 @Aspect 的类,把它们织入到对应的目标方法中!”
七、编写测试类
Demo3.java
package com.qcbyjy.test;import com.qcbyjy.demo3.OrderService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext_demo3.xml")
public class Demo3 {@Autowiredprivate OrderService orderService;@Testpublic void run1() {orderService.save();}
}
输出结果:
【AOP增强】方法执行前:记录日志...
业务层:保存订单...
完美!🎉
这说明我们的注解版 AOP 已经成功运行!
八、AOP 注解通知类型大全
Spring 支持五种常用的通知类型注解👇:
| 注解 | 通知类型 | 执行时机 |
|---|---|---|
@Before | 前置通知 | 目标方法执行前 |
@AfterReturning | 后置通知 | 方法成功执行后 |
@AfterThrowing | 异常通知 | 方法抛出异常后 |
@After | 最终通知 | 无论成功与否都会执行 |
@Around | 环绕通知 | 方法前后都能增强,需手动执行目标方法 |
✳️ 示例:多种通知的写法
package com.qcbyjy.demo3;import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;@Component
@Aspect
public class MyAnnoAspect {@Before("execution(* com.qcbyjy.demo3.OrderServiceImpl.save(..))")public void before() {System.out.println("【前置通知】方法即将执行...");}@AfterReturning("execution(* com.qcbyjy.demo3.OrderServiceImpl.save(..))")public void afterReturning() {System.out.println("【后置通知】方法执行成功!");}@AfterThrowing("execution(* com.qcbyjy.demo3.OrderServiceImpl.save(..))")public void afterThrowing() {System.out.println("【异常通知】方法执行出错!");}@After("execution(* com.qcbyjy.demo3.OrderServiceImpl.save(..))")public void after() {System.out.println("【最终通知】无论如何都会执行!");}@Around("execution(* com.qcbyjy.demo3.OrderServiceImpl.save(..))")public Object around(ProceedingJoinPoint pjp) throws Throwable {System.out.println("【环绕通知-前】准备执行方法...");Object result = pjp.proceed(); // 手动执行目标方法System.out.println("【环绕通知-后】方法执行完毕。");return result;}
}
执行结果:
【环绕通知-前】准备执行方法...
【前置通知】方法即将执行...
业务层:保存订单...
【后置通知】方法执行成功!
【最终通知】无论如何都会执行!
【环绕通知-后】方法执行完毕。
九、纯注解方式(无XML版)
Spring 也支持彻底不用 XML,只写注解。
SpringConfig.java
package com.qcbyjy.demo3;import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;@Configuration // 声明为配置类(代替xml)
@ComponentScan("com.qcbyjy.demo3") // 扫描包
@EnableAspectJAutoProxy // 开启AOP自动代理(代替 <aop:aspectj-autoproxy/>)
public class SpringConfig {
}
测试类修改为:
@ContextConfiguration(classes = SpringConfig.class)
到此为止,我们就实现了一个纯注解的 Spring AOP 项目!
🔚 十、总结对比
| 对比项 | XML 方式 | 注解方式 |
|---|---|---|
| 配置复杂度 | 需要手动写 <aop:aspect> | 更简洁,只需加注解 |
| 可读性 | XML 分散、冗长 | 注解集中、直观 |
| 推荐使用 | 旧项目/配置多场景 | ✅ 新项目首选 |
✅ 写在最后
通过注解方式实现 AOP,开发效率更高,代码更清晰。
尤其是结合 Spring Boot 时,几乎只需一个注解 @Aspect 就能搞定切面功能。
