spring中的AOP
AOP的XML配置
导入坐标
- 在pom中导入==aspectjweaver==的坐标
<dependency>
<groupId>org.aspectweaver</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.7</version>
</dependency>
在xml中导入aop的约束
<?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
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
配置步骤
-
把通知的bean也交给spring来管理
-
使用aop:config标签表明开始aop的配置
-
使用aop:aspect标签开始配置切面
id属性:是给切面提供的唯一标识
ref属性:是指定通知类bean的id
-
在aop:aspect标签内部使用对应的标签来配置通知的类型
aop:before:标识配置的前置通知
method属性:用于指定Logger类中哪个方法是前置通知
pointcut属性:用于指定切入点表达式,该表达式的含义指的是对业务层中哪些方法增强
切入点表达式的写法:
关键字:execution(表达式)
表达式:
访问修饰符 返回值 包名.包名...类名.方法名(参数列表)
标准的表达式写法:
public void com.itcast.service.imp.AccountServiceImpl.saveAccount()
访问修饰符可以省略 其余的可以使用通配符*
参数列表可以直接写数据类型:
基本数据类型直接写名称:int
引用类型包名.类名:java.lang.String
可以是同通配符*表示任意类型,但是必须有参数
可以使用..表示有误参数均可,任意类型都可
全通配写法:
* *..*.*(..) 实际开发中的常用写法:
切到业务层实现类下的所有方法
* com.itcast.service.imp. * . *(..)
<!--被切的bean-->
<bean id="accountService" class="com.itcast.service.imp.AccountServiceImp"></bean>
<!--切的方法所在的bean-->
<bean id="logger" class="com.itcast.utils.Logger"></bean>
<!--配置切面-->
<aop:config>
<aop:aspect id="aspect1" ref="logger"><!--在切面中引入切入方法所在的bean-->
<aop:before method="printLog" pointcut="public void com.*.*.*.saveAccount()"></aop:before>
</aop:aspect>
</aop:config>
通用的切入点表达式
方式一
- 将切入点表达式写在aop切面标签的内部
<aop:config>
<aop:aspect id="as1" ref="logger">
<!--配置通用的切入点表达式-->
<aop:pointcut id="pt1" expression="execution(* com.itcast.service.imp.*.*(..))"/>
<!--引用切入点表达式-->
<aop:before method="PringLog" pointcut-ref="pt1"></aop:before>
</aop:aspect>
</aop:config>
- ==注意==:当切入点表达式写在切面内部,只有该切面能够引用此切入点表达式
方式二
- 将切入点表达式写在aop切面标签的外部
<aop:config>
<!--配置通用的切入点表达式,只能写在所有切面的前面(xml的约束)-->
<aop:pointcut id="pt1" expression="execution(* com.itcast.service.imp.*.*(..))"/>
<!--配置切面-->
<aop:aspect id="as1" ref="logger">
<!--引用切入点表达式-->
<aop:before method="PringLog" pointcut-ref="pt1"></aop:before>
</aop:aspect>
</aop:config>
四种常用的通知
前置通知
- 标签:<aop:before>
- 作用时机:在切入点方法执行前执行
- 在环绕通知中的位置:在切入点方法执行前的代码
后置通知
- 标签:<aop:after-returning>
- 作用时机:在切入点方法执行之后,并且没有异常时执行
- 在环绕通知中的位置:在切入点方法执行后的代码
- ==注意==:后置通知和异常通知永远只能执行一个
异常通知
- 标签:<aop:after-throwing>
- 作用时机:在切入点方法执行之后,出现了异常时执行
- 在环绕通知中的位置:在catch中的代码
最终通知
- 标签:<aop:after>
- 作用时机:无论切入点方法是否正常执行,都会在最后执行
- 在环绕通知中的位置:在finally中的代码
环绕通知
- 注意:在环绕通知中要手动调用切入点的方法,否则只会执行通知中的方法
环绕通知的配置方式
- 和前置、后置通知一样,在<aop:aspect>标签中配置
<aop:config>
<!--配置切入点表达式-->
<aop:pointcut id="pt1" expression="execution(* com.itcast.service.imp.*.*(..))"></aop:pointcut>
<aop:aspect id="xx1" ref="logger">
<!--配置环绕通知-->
<aop:arround method="xxx" pointcut-ref="pt1"></aop:arround>
</aop:aspect>
</aop:config>
环绕通知的方法
//通知类
public class Logger{
//环绕通知
public Object arrountPrintLog(ProceedingJoinPoint pjp){
//返回值
Object rtValue=null;
try{
//获取参数列表
Object[] args = pjp.getArgs();
//前置通知
rtValue = pjp.proceed(args);//执行切入点方法
//后置通知
}catch(Throwable t){
//异常通知
throw new RuntimeException(t);
}finally{
//最终通知
}
return reValue;
}
}
-
==ProceedingJoinPoint==对象
用于在环绕通知中,获取参数列表,执行切入点方法