注意:最终通知是在后置通知之前执行的
使用Aop时需要导入aop约束 以及依赖aspectjweaver (这是动态代理的一种实现)
Aop:使用切面中的通知去增强切入点的功能 底层增强有JDK动态代理和cglib动态代理
将切面的通知切入到切入点执行
切面:写入通知的类
连接点:所有可以被增强的方法
切入点:真正被增强的方法
通知:用于增强的方法
前置通知: 在原来方法执行之前执行 标签 aop:before
后置通知: 在原来的方法执行之后执行 标签 aop:after-returning(注意最终通知是在后置通知之前执行的)
异常通知: 在原来的方法出现异常之后执行 标签 aop:after-throwing
(当原来方法异常被抛出之后就不能能执行这个方法)
最终通知:在方法执行之后执行,无论方法是否出现异常都要执行 也无论异常是否被抛出 标签 aop:after
(类似于tryCatch中的finally)
环绕通知:在方法之前和之后执行.也就是将目标方法在通知指定位置执行 标签:aop:around
环绕通知的方法和一般通知相比就是加入了ProceedingJoinPoint joinPoint参数,
然后joinPoint调用proceed()方法,执行目标方法。也就相当于动态代理执行方法,
要想使用这个动态代理,一定要导入依赖aspectjweaver(这个底层是jdk动态代理)
配置文件版演示:
<!--aop配置-->
<aop:config>
<!--配置切入点
切入点表达式:共四部分
1.返回值类型 如果为*则表示任意类型参数
2.类的全限定名 如果为*则表示改包下所有的类
3.方法名 如果为*则表示该类下所有方法
4.方法的参数类型 如果为*则表示任意参数类型(但必须有参数)
如果为..则表示任意类型参数也可以没有参数
-->
<!--id:此切入点的唯一标识
expression:切入点 注意他的表达式
-->
<aop:pointcut id="pt1" expression="execution(* com.ls.service.UserServiceImpl.add(..))"></aop:pointcut>
<aop:pointcut id="pt2" expression="execution(* com.ls.service.UserServiceImpl.update(..))"></aop:pointcut>
<!--配置切面 ref指的是切面代表的类在核心容器中的id-->
<aop:aspect ref="myAspect">
<!--配置通知
method:通知的方法名
pointcut-ref:切入点的id
-->
<!--前置通知-->
<aop:before method="permission" pointcut-ref="pt1"></aop:before>
<!--后置通知-->
<aop:after-returning method="after" pointcut-ref="pt1"></aop:after-returning>
<!--异常通知-->
<aop:after-throwing method="exception" pointcut-ref="pt1"></aop:after-throwing>
<!--最终通知-->
<aop:after method="MyFinally" pointcut-ref="pt1"></aop:after>
<!--环绕通知-->
<aop:around method="around" pointcut-ref="pt1"></aop:around>
</aop:aspect>
</aop:config>
注解版:(注意加载aop注解驱动 以及切面类要IOC)
注意使用aop注解加载切面通知的时候一定在配置文件要加载注解驱动<aop:aspectj-autoproxy/>
引入切面:@Aspect 相当于aspect标签(注意依然需要使用Component注解将类IOC存入核心容器中)
切入点:
第一种: @pointcut 在切面中定义一个新方法然后把PointCut注解加载上面 配置切入点
方法名就是切入点的唯一标识,相当于配置方法时aop:pointcut标签中的id
然后在通知注解上写入id
第二种:直接在通知的方法上面的注解中,直接定义切入点(execution) 一般使用第一种 可以重复使用切入点
通知:设置value属性来设置切入点
前置通知:@Before
后置通知:@AfterReturning
异常通知:@AfterThrowing
最终通知:@After
环绕通知:@Around
eg:
第一种方法:
第一步:定义一个方法作为切入点标识
@Pointcut("execution(* com.ls.service.AccountServiceImpl.transfer(..))")
public void pt1(){
}
第二步:定义通知
//后置
@AfterReturning("pt1()")
public void commit(){
System.out.println("后置方法使用");
}
第二种方法:
//前置
@Before("execution(* com.ls.service.AccountServiceImpl.transfer(..))")
public void star(){
System.out.println("前置方法使用");
}