先写一个模拟日志通知的Logger类并配置相应的注解标签
@Component("logger")//把logger类交给spring
@Aspect//表示当前是一个切面类
public class Logger {
@Before("execution(* com.lwh.service.impl.UserServiceImpl.*(..))")
public void printLog(){
System.out.println("前置通知日志打印了");
}
@AfterReturning("execution(* com.lwh.service.impl.UserServiceImpl.*(..))")
public void afterReturnPrint(){
System.out.println("后置通知打印了");
}
@AfterThrowing("execution(* com.lwh.service.impl.UserServiceImpl.*(..))")
public void afterThrowingPrint(){
System.out.println("异常通知打印了");
}
@After("execution(* com.lwh.service.impl.UserServiceImpl.*(..))")
public void afterPrint(){
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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.lwh"></context:component-scan>//扫描包
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>//自动完成创建代理织入切面的工作
</beans>
这样就完成了注解的四大通知的配置,接下来看看环绕通知的配置
首先要在bean.xml加上如下
<aop:config>
<aop:pointcut id="pt1" expression="execution(* com.lwh.service.impl.*.*(..))"/>
<aop:aspect id="logAdvice" ref="logger">
<aop:around method="arroundPrintLog" pointcut-ref="pt1"></aop:around>
</aop:aspect>
</aop:config>
然后在logger类中加上如下
public Object arroundPrintLog(ProceedingJoinPoint pjp){
Object rtValue=null;
try {
Object[] args=pjp.getArgs();
System.out.println("环绕前置通知开始打印");//以pjp.proceed为参照物
rtValue=pjp.proceed(args); //明确调用业务层方法:切入点方法
System.out.println("环绕后置置通知开始打印");
return rtValue;
}catch (Throwable e)
{ //catch表示异常通知
System.out.println("环绕异常通知开始打印");
throw new RuntimeException(e);
}
finally {//finall表示最终通知
System.out.println("环绕最终通知开始打印");
}
}
tips:
问题:当有环绕通知的时候 切入点方法就不会执行了 而前置通知还可以执行
分析:通过对比动态代理的环绕通知代码 发现动态代理有明确的切入点方法调用 而我们的代码中没有
解决:spring框架为我们提供了一个借口,ProceedingJoinPoint 该借口有一个方法proceed() 此方法就相当于明确调用切入点的方法 该接口可以作为环绕通知的方法参数 在程序执行时 spring会为我们提供该接口的实现类供我们使用