本文主要内容:基于XML和注解的AOP使用
AOP概念
- AOP:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率
- 个人理解:就是把我们程序重复的代码抽取出来,在需要执行的时候,使用动态代理的技术,在不修改源码的基础上,对我们的已有方法进行增强
基于XML的AOP配置
-
bean.xml引入头文件配置
-
Spring中基于XML的AOP配置
1.把通知Bean交给Spring管理
2.使用aop:config标签声明开始AOP配置
3.使用aop:aspect标签开始配置切面
①. id属性: 给切面提供唯一属性
②. ref属性:指定需要调用的方法的类的id
4.在aop:aspect标签内部使用对应的标签来配置通知的类型
1.aop:before(配置前置通知)、aop:after-returning(配置后置通知)、aop:after-throwing(配置异常通知)、aop:after(配置最终通知)、aop:around(配置环绕通知)
2.在这些aop:xx标签内部有3个属性:
①.method:指需要用来调用的增强方法(aop:aspect标签的ref指定类中的方法)
②.pointcut:用于指定切入点表达式,该表达式的含义指的是对业务层哪些方法增强
③.pointcut-ref:通过调用的方式来指明切入点表达式(见下文具体demo)
3.切入点表达式
1.语法:execution(表达式)
2.表达式:访问修饰符 访问值 包名.包名…类名.方法名(参数列表)
3.标准表达式写法:public void live.warlock.service.impl.AccountServiceImpl.saveAccount()
4.表达式可以有省略写法:
①. 访问修饰符可以省略
②. 返回值可以使用通配符表示任意修饰符 * live.warlock.service.impl.AccountServiceImpl.saveAccount()
③. 包名可以使用通配符表示任意包,但是有几个包就需要写几个() * ....AccountServiceImpl.saveAccount()
④. 包名可以使用…表示任意包与其子包 * …AccountServiceImpl.saveAccount()
⑤. 类名和方法名都可以使用 * ….()
⑥. 参数列表:
1.可以直接写数据类型
1.可以写基本数据类型 int
2.引用类写包名.类型 java.lang.String
2.可以使用通配符表示任意类型:()
3.有参、无参都统配:(…)
⑦. 全统配写法: ….(…)
⑧. 实际开发写法:写到业务层实现类然后用代替 * live.warlock.service.impl..(…) -
一个具体XML的AOP配置
aop:config
<aop:pointcut id=“pt” expression=“execution(* live.warlock.service..(…))”/>
<aop:aspect id=“logAdvice” ref=“logger”>
<aop:before method=“printLog” pointcut=“execution(* live.warlock.service..(…))”/><!-- 后置通知 在切入点方法正常执行之后执行--> <aop:after-returning method="AfterLog" pointcut-ref="pt"/> <!-- 异常通知 在切入点方法异常时执行--> <aop:after-throwing method="ThrowLog" pointcut-ref="pt"/> <!-- 最终通知--> <aop:after method="FinalLog" pointcut-ref="pt"/> <!-- 配置切入点表达式:写在aop:aspect标签内部:只能当前切面使用 写在aop:aspect外面:可以在任意切面使用 --> <aop:pointcut id="pt" expression="execution(* live.warlock.service.*.*(..))"/> <!-- 配置环绕通知 --> <aop:around method="aroundPrintLog" pointcut-ref="pt"/> </aop:aspect>
</aop:config>
-
环绕通知具体实现的问题与解决
问题:配置了环绕通知,切入点方法没有执行,而通知方法执行了
分析:通过对比动态代理的环绕通知方法,发现动态代理的环绕通知有明确的切入点方法调用,而我们没有
解决:Spring框架为我们提供了一个接口:ProceedingJoinPoint,该接口又有个proceed(),此方法相当于明确调用切入点方法,该接口可以作为环绕通知的方法参数,在程序执行时,Spring框架提供该接口的实现类供我们使用
Spring环绕通知:可以支持我们动态去配置通知
基于注解的AOP配置
常用注解介绍:
1. @Aspect:表示当前类是一个切面类
2. @Pointcut:可以声明一个方法为切入点方法方法
@Pointcut(“execution(* live.warlock.service..(…))”)
private void pt(){}
3. @Before(“pt()”):前置通知
4. @AfterReturning(“pt()”):后置通知
5. @AfterThrowing(“pt()”):异常通知
6. @After(“pt()”):最终通知
7. @Around(“pt()”):环绕通知
8. @EnableAspectJAutoProxy表示当前工程开启注解配置AOP