@After
作用
- 最终通知,不论程序前期执行成功还是失败,最后都要执行最终通知的切面功能
业务接口
package com.example.s04;
/**
* 业务接口
*/
public interface SomeService {
default String order(int orderNums){return null;}
}
业务实现类
package com.example.s04;
import org.springframework.stereotype.Service;
/**
* 业务实现类
*/
@Service
public class SomeServiceImpl implements SomeService {
@Override
public String order(int orderNums) {
System.out.println("预定图书: " + orderNums + "册");
return "order success";
}
}
切面类
package com.example.s04;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
/**
* 切面类
*/
@Aspect
@Component
public class SomeServiceAspect {
/**
* a.最终通知的方法规范
* 1.方法权限:public
* 2.方法返回值:void
* 3.方法名称:自定义
* 4.方法参数:没有,就算有也只能是JoinPoint类型
* 5.注解:需要用@After注解来表明通知的时机
* value参数:指定切入点表达式
*
* b.最终通知的示例
* public String order(int orderNums)
*/
@After(value = "execution(* com.example.s04.*.*(..))")
public void myAfter(){
System.out.println("最终通知切面被成功调用!");
}
}
applicationContext.xml
<!-- 添加包扫描 -->
<context:component-scan base-package="com.example.s04"/>
<!-- 绑定业务功能和切面功能-->
<aop:aspectj-autoproxy/>
测试1
- 程序正常执行
package com.example.test;
import com.example.s04.SomeService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestAfter {
//测试最终通知
@Test
public void testAfter(){
//创建Spring容器
ApplicationContext ac = new ClassPathXmlApplicationContext("s04/applicationContext.xml");
//获取jdk动态代理对象
SomeService agent = (SomeService) ac.getBean("someServiceImpl");
//调用业务方法(基本业务功能 + 切面业务功能)
String res = agent.order(10);
System.out.println("返回结果: " + res);
}
}
测试结果
- 此时程序正常运行,最终通知的切面功能在目标方法执行后被调用
预定图书: 10册
最终通知切面被成功调用!
返回结果: order success
Process finished with exit code 0
测试2
- 目标方法在执行过程中出现异常,将业务实现类做如下修改
/**
* 业务实现类
*/
@Service
public class SomeServiceImpl implements SomeService {
@Override
public String order(int orderNums) {
System.out.println("预定图书: " + orderNums + "册");
//目标方法在返回值前出错
System.out.println(1/0);
return "order success";
}
}
测试结果
- 由执行结果可以看出,虽然程序崩溃,但是最终通知还是正常执行
测试3
- 为了对比后置通知(@AfterReturning)和最终通知(@After)的区别,演示当目标方法后是后置通知而不是最终通知的情况。将@AfterReturning篇的博文的业务实现类做如下修改
/**
* 业务实现类
*/
@Service
public class SomeServiceImpl implements SomeService{
@Override
public String doSome(int orderNums) {
System.out.println("预定图书: " + orderNums + "册");
//程序在返回值前崩溃
System.out.println(1/0);
return "order success";
}
}
测试输出
- 在目标方法出错后,后置通知没有执行
@Pointcut
作用
- 为切入点表达式起别名
切面类
- 将上述切面类做如下修改,此时的空方法名myCut即为自定义的切入点表达式的别名,用myCut()来替换原来的切入点表达式即可
/**
* 切面类
*/
@Aspect
@Component
public class SomeServiceAspect {
@After(value = "myCut()")
public void myAfter(){
System.out.println("最终通知切面被成功调用!");
}
/**
* 为切入点表达式起别名:
* 使用@Pointcut注解
* value属性:切入点表达式
* 定义一个公共访问权限,无返回值的空方法,方法名即为切入点表达式的别名
*/
@Pointcut(value = "execution(* com.example.s04.*.*(..))")
public void myCut(){}
}
相关文章
暂无评论...