环绕通知
Spring AOP 五种通知类型
Spring AOP 一共提供5种类型的通知:
before 前置通知, 在目标方法运行前, 先去执行 切面类 的 切面方法
after 后置通知,在目标方法运行后,再执行切面类的切面方法
after return 后置返回通知,在目标方法返回数据以后,再执行切面类的切面方法
after throwing 异常通知, 在目标方法抛出异常后, 再执行切面类的切面方法
around 环绕通知,最为强around 环绕通知,最为强大,可自定义通知执行时机,可决定目标方法是否运行
其中 after 和 after return 本质上没有区别,其执行的先后顺序由 applicationContext 中的 标签顺序决定
功能最强大的即为 around 环绕通知。在环绕通知的 切面方法中,可以控制目标方法是否执行,可以在目标方法运行前,目标方法运行后执行,还可以获得目标方法的返回类型。可以说,环绕通知包括了其他四种通知的全部功能。
定义目标类与目标方法
maven 依赖与 “第一个 Spring AOP 应用” 里面一样,这里不再重复
定义一个 UserService 类 和 UserDao 类。
public class UserService {
private UserDao userDao;
public void createUser(){
System.out.println("执行创建用户业务逻辑");
userDao.insert();
}
public String generateRandomPassword(String type , Integer length){
System.out.println("按" + type + "方式生成"+ length + "位随机密码");
return "Zxcquei1";
}
// getter 和 setter 方法 省略
}
public class UserDao {
public void insert(){
System.out.println("新增用户数据");
}
}
新的需求
假设有这么一个需求,需要获取 UserService 运行过程 的执行时间。
Spring AOP 环绕通知 实现新需求
定义切面类
切面方法为 check, 传入参数不再是 JoinPoint 类型, 而是 ProceedingJoinPoint 类型。 ProceedingJoinPoint 更加强大,主要体现在 其 proceed 方法, 其作用是执行目标方法。如果不调用 proceed 方法,则不执行 proceed 方法。再加上 ProceedingJoinPoint 本身也支持 getTarget, getSignature, getArgs 方法, 也就是说 环绕通知的切面方法可以控制目标方法是否执行,可以在目标方法执行前,后分别进行扩展,可以获取目标方法的返回值,可以说是非常强大。
public class MethodChecker {
//ProceedingJoinPoint 是 JoinPoint 的升级版, 在原有功能外, 还可以控制目标方法是否执行
public Object check(ProceedingJoinPoint pjp) throws Throwable{
try {
long startTime = new Date().getTime();
Object ret = pjp.proceed();//执行目标方法
long endTime = new Date().getTime();
long duration = endTime - startTime;
if (duration>=1000){
String className = pjp.getTarget().getClass().getName();//获取目标类的名称
String methodName = pjp.getSignature().getName();//获取目标方法的名称
Object[] args = pjp.getArgs();//获取目标方法参数
SimpleDateFormat sdt= new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSSS");
String now = sdt.format(new Date());
System.out.println("========"+now + " : "+ className+" : "+methodName+ " 参数个数 : " + args.length +" ( "+ duration +" ms)"+"========");
}
return ret;
} catch (Throwable throwable) {
System.out.println("Exception message : "+ throwable.getMessage());
throw throwable;
}
}
}
配置 applicationContext.xml
环绕通知 使用 <aop:around> 标签 进行配置
<?xml version="1.0" encoding="UTF-8"?>
<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"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="userDao" class="indi.chester.spring.aop.dao.UserDao"/>
<bean id="userService" class="indi.chester.spring.aop.service.UserService">
<property name="userDao" ref="userDao"/>
</bean>
<!-- 切面类 -->
<bean id="methodChecker" class="indi.chester.spring.aop.aspect.MethodChecker"/>
<aop:config>
<aop:pointcut id="pointcut" expression="execution(public * indi.chester..*.*(..))"/>
<aop:aspect ref="methodChecker">
<!-- 环绕通知,使用 methodChecker.check 方法进行环绕通知, 切点为 pointcut -->
<aop:around method="check" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
</beans>
测试一下:
public class SpringApplication {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
UserService userService = context.getBean("userService", UserService.class);
userService.createUser();
}
}
运行结果:
执行创建用户业务逻辑
新增用户数据
========2022-02-19 10:22:02 0037 : indi.chester.spring.aop.service.UserService : createUser
Last updated