前置通知@Before
运行结果:
后置通知@After
和前置通知类似,只是在原始方法执行后执行通知,下面直接来看运行结果
运行结果:
环绕通知@Around
运行结果:
注意事项:
注意事项 |
1.环绕通知必须有ProceedingJoinPoint类型的方法形参,用于执行原始方法 |
2.如果没有这个形参,原始方法不执行 |
3.由于未知原始方法是否会抛异常,因此这个切面方法必须抛异常 |
4.如果原始方法有返回值,切面方法的返回值必须是Object类型 |
5.如果原始方法是void类型,切面方法也可以是Object类型 |
返回后通知@AfterReturning
运行结果:
@After和@AfterReturning对比
@After | @AfterReturning |
原始方法发生异常时仍然通知 | 原始方法正常return才通知 |
抛出异常后通知@AfterThrowing
运行结果:
6.案例:使用@Around统计业务层方法执行时间
1.准备工作
准备好了实体类,mapper接口和service和和实现类,以及三个配置文件和jdbc.properties文件,下面是通知类(使用Signature类获取执行的方法有关信息)
@Component @Aspect public class Advice { // 为两个方法设置切入点 @Pointcut("execution(* demo8.service.*Service.select*(..))") private void selectPt() { } // 设置切面 @Around("selectPt()") public Object method(ProceedingJoinPoint point) throws Throwable { Signature signature = point.getSignature(); String methodName = signature.getName(); // 获取方法名 String typeName = signature.getDeclaringTypeName(); // 获取方法类型 long startTime = System.currentTimeMillis(); // 获取执行前的系统时间 Object o = null; for (int i = 0; i < 1000; i++) { o = point.proceed(); } long endTime = System.currentTimeMillis(); // 获取执行后的系统时间 System.out.println("执行"+typeName+"类型的"+methodName+"方法花费时间:" + (endTime - startTime) + "ms"); return o; } }
测试类:
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = SpringConfig.class) public class UserServiceTest { @Autowired private UserService service; @Test public void testSelectAll() { List<User> users = service.selectAll(); System.out.println(users); System.out.println(users.size()); // 获取方法有关信息 } @Test public void testSelectById() { User user = service.selectById(2); System.out.println(user); } }
测试结果:
7.AOP获取通知数据
获取方法参数
五种通知都可以获取方法参数,一般使用JoinPoint类型形参的getArgs()方法,在环绕通知中(@Around)使用ProceedJoinPoint类型的getArgs()方法。
举例:
(1)JoinPoint对象
@Before("fn1()") public void before(JoinPoint joinPoint) { Object[] args = joinPoint.getArgs(); // 1.前置通知获取切入点方法参数 System.out.println(Arrays.toString(args)); System.out.println("before ..."); }
业务层接口和实现类:
主类和运行结果:
(2)ProceedJoinPoint对象
获取方法返回值
只有返回后通知@AfterReturning和环绕通知@Around可以获取
(1)环绕通知
(2)返回后通知
使用Object类型的方法形参,并在注解上加returning = 形参名称
获取异常信息
只有抛出异常后通知@AfterThrowing和环绕通知@Around可以获取
(1)环绕通知
首先在serviceImpl抛出一个异常
(2)抛出异常后通知
使用Throwable 类型的形参,并在注解上加上throwing = 形参名称
8.案例:使用@Around处理参数中的字符串
9.AOP总结:
这篇文章主要介绍了AOP面向切面编程的概念和作用,以及切入点、通知、切面的内容,后面介绍通知的类别(5类),最后介绍在通知中如何获取并处理数据。
三、结语
AOP是spring的核心思想之一,前面学习了IOC(控制反转),至此开始越来越了解spring的工作机制。