切入点表达式
就是指定对哪些类的哪些方法进行增强
切入点表达式的几种写法
关键字:execution(表达式)
表达式语法:[访问修饰符] 返回值类型 包名.类名.方法名(参数)
标准切入点表达式写法:
execution(void com.mg.service.impl.AccountServiceImpl.saveAccount())
-
访问修饰符可省略
execution(void com.mg.service.impl.AccountServiceImpl.saveAccount())
-
返回值可用通配符表示任意返回值
execution(* com.mg.service.impl.AccountServiceImpl.saveAccount())
-
包名可用通配符表示任意包,但有几级包就需要写几个
execution(* *.*.*.*.AccountServiceImpl.saveAccount())
-
包名可用 .. 表示当前包及其子包
<!--execution(* com..AccountServiceImpl.saveAccount())--> execution(* *..AccountServiceImpl.saveAccount())
-
类名和方法名都可以使用 * 来匹配
execution(* *..*.*())
-
参数列表
<!--可以直接写数据类型,基本类型直接写名称(如:int),引用类型写包名.类名(如:com.mg.dao.AccountDao)--> execution(* *..*.*(int)) 匹配只有一个参数,并且类型为int的方法 <!--可使用通配符表示任意类型,但必须有参数--> execution(* *..*.*(*)) 匹配只有一个参数,不论参数是何种类型 <!--可以使用 .. 表示有无参数均可,有参数可以是任意类型--> execution(* *..*.*(..)) 全通配写法,匹配所有方法 注: 实际开发中,我们都是对业务层的方法进行增强,所以切入点表达式都是切到业务层实现类下的所有方法。 execution(* com.mg.service.impl.*.*(..))
通用化切入点表达式
aop:pointcut:当书写多个通知类型时,切入点表达式如果相同就不需要书写多次了
<aop:config>
<!--此标签写在aop:aspect外部时所有切换都可以使用,写在外面时要注意位置,必须在aop:pointcut标签上面-->
<aop:pointcut id="pt1" expression="execution(* com.mg.service.impl.*.*(..))"></aop:pointcut>
<aop:aspect id="logAdvice" ref="logger">
<!--此标签可以写在aop:aspect内部,但只能当前切面使用-->
<!--<aop:pointcut id="pt1" expression="execution(* com.mg.service.impl.*.*(..))"/>-->
<aop:before method="printLog" pointcut-ref="pt1"></aop:before>
<aop:after-returning method="printLog" pointcut-ref="pt1"></aop:after-returning>
</aop:aspect>
</aop:config>
细节:
<aop:pointcut id="" expression=""></aop:pointcut>
属性:
id: 用于给切入点表达式提供一个唯一标识
expression:用于定义切入点表达式。
通知类型
前置通知
aop:before
作用:用于配置前置通知。 属性: method:用于指定通知类中的增强方法名称 ponitcut-ref:用于指定切入点的表达式的引用 poinitcut:用于指定切入点表达式 执行时间点:切入点方法执行之前执行
<aop:before method="before" pointcut-ref="pt1"></aop:before>
后置通知
aop:after-returning
作用:用于配置后置通知,切入点方法正常执行之后执行 属性: method: 指定通知中方法的名称。 pointct: 定义切入点表达式 pointcut-ref: 指定切入点表达式的引用 执行时间点:切入点方法正常执行之后。它和异常通知只能有一个执行
<aop:after-returning method="afterReturning" pointcut-ref="pt1"></aop:after-returning>
异常通知
aop:after-throwing
作用:用于配置异常通知 属性: method: 指定通知中方法的名称。 pointct: 定义切入点表达式 pointcut-ref: 指定切入点表达式的引用 执行时间点:切入点方法执行产生异常后执行。它和后置通知只能执行一个
<aop:after-throwing method="afterThrowing" pointcut-ref="pt1"></aop:after-throwing>
最终通知
aop:after
作用:用于配置最终通知 属性: method: 指定通知中方法的名称。 pointct: 定义切入点表达式 pointcut-ref: 指定切入点表达式的引用 执行时间点:无论切入点方法执行时是否有异常,它都会在其后面执行。
<aop:after method="after" pointcut-ref="pt1"></aop:after>
环绕通知
aop:around
作用:用于配置环绕通知 属性: method:指定通知中方法的名称。 pointct:定义切入点表达式 pointcut-ref:指定切入点表达式的引用 说明:它是 spring 框架为我们提供的一种可以在代码中手动控制增强代码什么时候执行的方式。 注意:通常情况下,环绕通知都是独立使用的
示例:
通知类:
public class Logger1 {
public Object arroundLog(ProceedingJoinPoint pjp) {
Object val = null;
Object[] args = pjp.getArgs();
try {
//增强代码写在方法调用之前就是前置通知
System.out.println("前置通知");
val = pjp.proceed(args);//代表调用切入点方法
//增强代码写在方法调用之后就是后置通知
System.out.println("后置通知");
} catch (Throwable throwable) {
//增强代码写在catch中就是异常通知
System.out.println("异常通知");
throwable.printStackTrace();
}finally {
//增强代码写在finally中就是最终通知
System.out.println("最终通知");
}
return val;
}
}
ProceedingJoinPoint:
Spring为我们提供的接口,他有一个方法proceed 代表调用切入点方法,该接口可以作为环绕通知的参数,在程序执行时,Spring会为我们提供该接口的实现类供我们使用
配置文件:
<?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 id="accountService" class="com.mg.service.impl.AccountServiceImpl"></bean>
<bean id="logger1" class="com.mg.log.Logger1"></bean>
<aop:config>
<aop:pointcut id="pt1" expression="execution(* com.mg.service.impl.*.*(..))"/>
<aop:aspect id="logAdvice1" ref="logger1">
<aop:around method="arroundLog" pointcut-ref="pt1"></aop:around>
</aop:aspect>
</aop:config>
</beans>