**
Advice
**
AOP的advice分为五种:
前置通知
后置通知
异常通知
最终通知
环绕通知
先看前四种通知,直接上代码
模拟一个业务层
/**
* 账户的业务层实现类
*/
public class AccountServiceImpl implements AccountService {
public void saveAccount() {
System.out.println("执行了保存");
}
}
切面
public class Logger {
/**
* 前置通知
*/
public void beforePrintLog(){
System.out.println("前置通知");
}
/**
* 后置通知
*/
public void afterPrintLog(){
System.out.println("后置通知");
}
/**
* 异常通知
*/
public void afterExceptionPrintLog(){
System.out.println("异常通知");
}
/**
* 最终通知
*/
public void finalPrintLog(){
System.out.println("最终通知");
}
}
bean.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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 配置spring的ioc,把-service对象配置进来-->
<bean id="accountService" class="Gao.service.impl.AccountServiceImpl"></bean>
<!-- 配置Logger类 -->
<bean id="logger" class="Gao.utils.Logger"></bean>
<!--配置AOP-->
<aop:config>
<!--配置切面 -->
<aop:aspect id="logAdvice" ref="logger">
<!--配置切入点表达式,id属性用于指定表达式的唯一标识-->
<aop:pointcut id ="pt1" expression="execution(* Gao.service.impl.*.*(..))"></aop:pointcut>
<!-- 配置通知的类型,并且建立通知方法和切入点方法的关联-->
<aop:before method="beforePrintLog" pointcut-ref="pt1"></aop:before>
<!-- 配置通知的类型,并且建立通知方法和切入点方法的关联-->
<aop:after-returning method="afterPrintLog" pointcut-ref="pt1"></aop:after-returning>
<!-- 配置通知的类型,并且建立通知方法和切入点方法的关联-->
<aop:after-throwing method="afterExceptionPrintLog" pointcut-ref="pt1"></aop:after-throwing>
<!-- 配置通知的类型,并且建立通知方法和切入点方法的关联-->
<aop:after method="finalPrintLog" pointcut-ref="pt1"></aop:after>
</aop:aspect>
</aop:config>
</beans>
test
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
AccountService as = (AccountService) ac.getBean("accountService");
as.saveAccount();
}
结果
前置通知
执行了保存
后置通知
最终通知
结果显而易见,在执行方法前执行了前置通知,执行完方法后执行了后置通知和最终通知,而如果执行方法过程中出现异常,那么最终通知不会执行,反而会执行异常通知(最终通知和异常通知只可以执行一个)
环绕通知
这个通知与前面的通知有很大区别,我们先看代码:
bean.xml
<!-- 配置环绕通知-->
<aop:around method="aroundPrintLog" pointcut-ref="pt1"></aop:around>
切面
public Object aroundPrintLog(ProceedingJoinPoint pjp){
Object rtValue=null;
try {
Object[] args=pjp.getArgs();//得到方法执行所要的参数
System.out.println("前置通知");
rtValue=pjp.proceed(args);//明确调用业务层方法(切入点方法)
System.out.println("后置通知");
return rtValue;
}catch (Throwable t){
System.out.println("异常通知");
throw new RuntimeException (t);
}finally {
System.out.println("最终通知");
}
}
结果:
前置通知
执行了保存
后置通知
最终通知
虽然结果一样,但是可以看出环绕通知和动态代理有一点相似,目标方法的调用由环绕通知决定,这一点与前面四个通知都不同。