Spring AOP
)
1. SpringAOP概述
基于动态代理技术,在层与层之间加入功能型代码,在不改变目标层代码的前提下进行功能的增强,这样的夹在层与层之间的部分称之为切面,这样的开发技术叫做面向切面编程AOP。
2. SpringAOP中的基本概念
a. 连接点
对目标层中方法的调用过程叫做连接点
b. 切入点
基于切入点规则筛选出符合要求的连接点,这些连接点将被Spring内置的动态代理拦截进行增强,这些被筛选出来的连接点叫做切入点。
c. 切面
动态代理拦截下切入点后交给开发者定义的类来处理,这样的类称之为切面。
d. 通知
切面类中真正处理增强功能的方法叫通知。
e. 目标对象
被动态代理代理的真正要调用的对象叫做目标对象。真正要被访问的方法叫目标方法。
f. 织入
将切面逻辑加入原有逻辑的过程称之为织入。
3. SpringAOP的入门案例
a. 创建项目并导入相关开发包
b. 编写Spring配置文件,并导入beans context aop约束
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
">
</beans>
c. 开发程序结构
d. 开发一个切面类
开一个普通的类,要在Spring容器中注册成一个bean
package cn.xxxx.aspect;
import org.springframework.stereotype.Component;
@Component
public class FirstAspect {
}
e. 开发通知方法
在切面类中开发一个方法作为通知
package cn.xxxx.aspect;
import org.springframework.stereotype.Component;
@Component
public class FirstAspect {
public void myBefore(){
System.out.println("before...");
}
}
f. 配置Spring注解切面类和通知方法
<aop:config>
<aop:aspect ref="firstAspect">
<aop:before method="myBefore" pointcut="within(cn.xxxx.service.UserServiceImpl)"/>
</aop:aspect>
</aop:config>
g. 进行测试
4. 切入点表达式
a. within表达式
这是一种粗粒度的切入点表达式,只能控制到类。
具体语法结构为:
within(包名.类名) |
---|
i. 普通写法
将指定包下的指定类中的所有方法拦截作为切入点
within(cn.xxxx.service.UserServiceImpl) |
---|
ii. 号通配符代替类
使用号通配符代表类名,匹配任何类名
注意,只包含指定包,不包括子孙包
within(cn.xxxx.service.*) |
---|
iii. 号通配符代替包
使用号通配符代表某一级包,匹配任何包名
within(cn.xxxx..) |
---|
iv. …*通配符匹配指定包及其子孙包
匹配指定包及其子孙包下所有的类
within(cn.xxxx.service…*) |
---|
b. execution表达式
细粒度的切入点表达式,可以控制到方法级别。
基本的语法:
关键字(返回值类型 包名 类名 方法名(参数类型列表)) |
---|
i. 基本用法
明确指向一个方法,截这个方法
execution(void cn.xxxx.service.UserServiceImpl.addUser(cn.xxxx.domain.User); |
---|
5. 五大通知的类型
SpringAOP通知共有五种,称之为SpringAOP的五大通知类型
a. 前置通知 before
通过aop:before来定义
在目标方法执行之前执行的通知
前置通知可以选择性的接受一个JoinPoint类型的参数,要注意,如果接受,则此参数必须位于通知方法参数列表的第一位。
可以通过这个JoinPoint参数来获取目标对象和目标方法相关的信息。
//目标对象
Objectobj=jp.getTarget();
//目标方法
MethodSignaturesignature=(MethodSignature)jp.getSignature();//目标方法的签名信息
Methodmethod=signature.getMethod();//目标方法
b. 环绕通知 around
在目标方法执行之前和之后都要执行的通知
通过aop:around来配置
环绕通知需要手动调用目标方法去执行,如果不调用目标方法不执行。
环绕通知可以接受一个ProceedingJoinPoint类型的参数,如果接受必须保证此参数位于通知方法参数列表的第一位。
ProceedingJoinPoint是JoinPoint的子类,通过此类对象仍然可以获取目标对象和目标方法的信息。
**只有环绕通知可以接受ProceedingJoinPoint,其类型通知不可接受。
此外,此对象可以用调用目标方法。
ObjectretuObj=pjp.proceed(); |
---|
调用目标方法得到的返回值必须手工返回给调用者,否则调用者得不到返回值。
甚至可以在这个过程中改变返回值。
虽然环绕通知可以实现
控制目标方法是否执行
控制目标方法的返回值是否返回
改变返回
这样的效果,但在使用时要慎重,不能破坏了高内聚 低耦合的目标。
c.后置通知
在目标方法成功执行之后执行的通知
aop:after-returing
后置通知中可以接受JoinPoint类型的参数,通过此参数可以获取目标对象和目标方法相关的信息。
一旦接受此JoinPoint作为参数,则此参数必须出现在通知方法参数列表的第一位
在后置通知可以获取目标方法执行过后的返回值
<aop:after-returning method="myAfterReturing" pointcut-ref="pc01" returning="retObj"/>
d. 异常通知
当目标方法执行抛出异常时执行的通知
aop:after-throwing
在异常通知中可以接受JoinPoint类型的参数,通过此参数可以获取目标对象和目标方法相关的信息。
一旦接受此JoinPoint作为参数,则此参数必须出现在通知方法参数列表的第一位
在异常通知中可以获取目标方法执行时抛出的异常对象
<aop:after-throwingmethod="myAfterThrowing"pointcut-ref="pc01"throwing="e"/>
e. 最终通知
在目标方法执行之后执行的通知,和后置通知不同之处在于,后置通知实在目标方法成功执行后才会执行的通知,一旦抛异常后置通知是不执行的,而最终通知目标方法是否执行成功都会执行。
aop:after
在最终通知中可以接受JoinPoint类型的参数,通过此参数可以获取目标对象和目标方法相关的信息。
一旦接受此JoinPoint作为参数,则此参数必须出现在通知方法参数列表的第一位
6. 通知的执行顺序
通知的执行顺序和通知的配置顺序有关,不用记,但无论怎样前置通知、环绕前通知一定在目标方法执行之前执行,后置通知 环绕后通知 最终通知 异常通知一定在目标方法执行之后执行。
7. 多个通知的执行顺序
多个通知按照配置顺序依次执行,执行过程采用责任链模式,像多层方法调用一样执行。
8. SpringAOP内置的动态代理
a. 默认采用Java的动态代理
b. 如果目标对象没有实现过接口,则自动切换为CGLIB动态代理
c. 只需要配置一下就可以强制要求SpringAOP无论是否有接口都用CGLIB动态代理
<aop:config proxy-targrt-class="true">
</aop:config>
今天先聊到这里,我们下期见
------在下亦从文,弃武从文