Spring之面向切面编程(AOP语法XML和注解开发)
AOP为Aspect Oriented Programming的缩写,意思为面向切面编程。通过预编译方式和运行期动态代理实现程序功能统一维护的一种技术。
基于jdk的动态代理
代理对象和目标对象二者兄弟关系,实现相同接口
目标对象接口TargetInterface:
目标对象Target:
通知类Advice:增强代码,增强目标对象功能
代理类:我们的目标是生成代理对象
代理类中以下部分会被Spring的配置文件代替:
代理对象包名和目标对象不一致,目标对象的包名是com.sun.proxy...
基于cglib的动态代理(主要使用本方式)
使用增强器帮我们在内存中生成代理对象,目标对象不能是最终类,代理对象和目标对象的关系是父子关系,子可强制类型转换为父类型,代理对象包名与目标对象一致,Spring默认使用JDK方式,但我们通过配置让Spring优先使用本方式
本方式不需要接口:
目标对象Target:
通知类Advice:增强代码,增强目标对象功能
代理类:我们的目标是生成代理对象
AOP相关概念:
Spring的AOP实现底层就是对上面的动态代理的代码进行了封装,封装后我们只需要对关注的部分进行编写,并通过配置的方式完成指定目标的方法增强。
AOP相关术语:
其中比较重要的有:
JoinPoint连接点:目标对象中的所有方法,连接点是可以被增强的方法,只要它可以被增强,那就被称为连接点。
PointCut切(入)点:实际被增强的方法
Advice通知:增强的代码,要加到Target方法上的逻辑。
Aspect切面:Advice(通知)和PointCut(切入点)的结合关系被称作切面,即插入的代码与原代码结合的位置如:
Advice(通知)代码在PointCut(切入点)代码前:这两段代码组成切面一
Advice(通知)代码在PointCut(切入点)代码后:这两段代码组成切面二
Weaving织入:切面处的拼接(不需要我们做),打个比方,我们想增强某个方法,此时这个方法是身体的【PointCut切(入)点】,我们拿手术刀把这里划开,把增强代码【Advice通知】塞进去,这个拼接点被称为【Aspect切面】,然后我们要在保证这次手术真的完成了目标并且程序正常运行,需要把伤口缝合并让它痊愈【Weaving织入】
切点表达式写法:
..任意包括没有,*任意不包括没有
无返回值无参数的proxy.aop.Target.method()方法:
execution(public void proxy.aop.Target.method())
无返回值任意参数的proxy.aop.Target类下的任意方法:
execution(public void proxy.aop.Target.*(..))
proxy.aop包下的任意类的任意方法,有无参数返回值无所谓:
execution(* proxy.aop..(..))【最常用】
proxy.aop包及其子包下的任意类的任意方法,有无参数返回值无所谓:
execution(public void proxy.aop...(..))
一切都那么的任意:
execution(* ...*(..))
AOP开发事项
切面类代表的不是【Aspect切面】,切面类内部封装了【Advice通知】的方法,为注解类做准备,因为注解最后要被写到载体上(类/方法/变量),但是【Aspect切面】没有实体,所以配到【Advice通知】内
基于XML开发AOP:
导入AOP坐标
创建目标接口和目标类(内部有切点)
创建通知类
利用IOC和AOP(包括JDK方式和CGLIB方式)完成配置例一:before通知
利用IOC和AOP完成配置例二:四种通知
利用IOC和AOP完成配置例三:环绕通知(不与其他四种通知共存)
通知的类型
环绕增强可以替代上述四个通知,只不过需要手写代码,它有明确的切入点方法的执行,可以用于增强返回值:
配置文件:
结果:
切点表达式的抽取:
抽取代码:
结果:
设置jdk或者cglib:
强制使用cglib作为代理方式:
基于注解开发AOP:
创建目标接口和目标类
与基于XML方式一致
创建切面类
与基于XML方式一致
目标类对象和切面类对象加入Spring容器
这是一个切面:
这也是一个切面:
在切面类中使用注解配置织入关系:建议只使用环绕通知,其他的有bug
在配置文件中开启组件扫描和AOP的自动处理
组件扫描无法识别代理注释,开启aop自动代理可以让代理注释可用
执行结果:
切点表达式的抽取:
建立一个空方法
配置特定增强:
一次最终增强和一次环绕增强,会有两次最终增强。