博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
《Spring In Action(第4版)》阅读总结(二)Spring AOP
阅读量:6436 次
发布时间:2019-06-23

本文共 5443 字,大约阅读时间需要 18 分钟。

面向切面编程的Spring

  1. 面向切面编程的基本原理
  2. 通过POJO创建切面
  3. 使用@AspectJ注解
  4. 为AspectJ切面注入依赖

面向切面编程

解决横切关注点与业务逻辑相分离

AOP术语
通知(Advice):切面的工作目标,定义切面执行的工作以及何时执行。如调用前、调用后等;通知共分为5类
前置通知(Before):在目标方法被调用之前调用通知功能;
后置通知(After):在目标方法完成之后后调用通知,此时不会关心方法的输出是什么;
返回通知(After-returning):在目标方法成功调用之后调用通知;
异常通知(After-throwing):在目标方法抛出异常之后调用通知
环绕通知(Aroud):通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为。

//AOP通知执行顺序 仅供参考try {    try {        before();        //前置通知,目标方法前执行        around();        //环绕通知,环绕目标方法,目标方法前后执行    catch (Exception e) {        after();         //后置通知,最终执行        throw e;         //继续抛出异常,执行异常通知    }    after();    afterReturning();    //返回通知,目标方法成功后执行} catch (Exception e) {    afterThrowing();     //异常通知,方法抛出异常后执行}

连接点(Join point):程序执行过程中能够插入切面的一个点。可以是调用方法时,抛出异常时,甚至修改一个字段时。切面代码可以利用这些点插入到应用的正常流程之中,并添加新的行为。

切点(Pointcut):切点的定义会匹配通知所要织入的一个或多个连接点。通常使用明确的类和方法名称,或利用正则表达式定义所匹配的类和方法名称来指定这些切点。有些AOP框架允许我们创建动态的切点,可以根据运行时的决策(比如方法的参数值)来决定是否应用通知。

切面(Aspect):切面是通知和切点的结合。通知和切点共同定义了切面的全部内容——它是什么,在何时和何处完成其功能。

引入(introduction):引入允许我们向现有的类添加新方法或属性。无需改变现有的类的情况下,让他们具有新的行为和状态。

织入(Weaving):织入是把切面应用到目标对象并创建新的代理对象的过程。切面在指定的连接点被织入到目标对象中。在目标对象的生命周期里有多个点可以进行织入。

编译器:切面在目标类编译时被织入。这种方式需要特殊的编译器。AspectJ的织入编译器就是以这种方式织入切面的。
类加载器:切面在被目标类加载到JVM时被织入。这种方式需要特殊的类加载器(ClassLoader),它可以再目标类被引入应用之前增强该目标类的字节码。AspectJ 5的加载时织入(load-time weaving,LTW)就支持以这种方式织入切面。
运行期:切面在应用运行的某个时刻被织入。一般情况下,在织入切面时,AOP容器会为目标对象动态地创建一个代理对象。Spring AOP就是以这种方式织入切面的。

Spring对AOP的支持

并非所有AOP框架都是相同的,她们在连接点模型上可能有强弱之分。有些允许在字段修饰符级别应用通知,而另一些只支持与方法调用相关的连接点。它们织入切面的方式和时机也有所不同。但是无论如何,创建切点来定义切面所织入的连接点是AOP框架的基本功能。

关于Spring AOP,Spring 和 AspectJ项目之间有大量的协作,Spring AOP在很多方面借鉴了AspectJ项目。
Spring 提供4种类型的AOP支持

  1. 基于代理的经典Spring AOP:已过时
  2. 纯POJO切面:借助Spring的aop命名空间,将纯POJO转换为切面。需要XMl配置,Spring AOP显式声明
  3. @Aspect注解的切面:Spring AOP提供注解声明切面,不需要XML配置。
  4. 注入式AspectJ切面:AOP需求超过简单的方法调用(如构造器或属性拦截),考虑使用AspectJ来实现切面。

Spring通知是Java编写的

Spring创建的通知都是标准Java编写。使用与普通Java开发的集成开发环境(IDE)来开发切面。定义通知所应用的切面可使用注解或XML配置。

Spring在运行时通知对象

通过在代理类中包裹切面,Spring在运行期把切面织入到Spring管理的bean中。

代理类封装了目标类,并拦截被通知方法的调用,再把调用转发给真正的目标bean。当代理拦截到方法调用时,在调用目标bean方法之前,会执行切面逻辑。如下图:

clipboard.png

因为Spring运行时才创建代理对象,不需要特殊的编译器来织入Spring AOP的切面。

Spring只支持方法级别的连接点

通过支持各种AOP方案可以支持多种连接点模型。因为Spring基于动态代理,所以Spring只支持方法连接点,缺少字段、构造器连接点的支持,无法创建细粒度的通知。

通过切点来选择连接点

切点用于定位在何处应用切面的通知。通知和切点是切面的最基本元素,了解如何编写切点非常重要

Spring AOP 使用AspectJ的切点表达式语言来定义切点。但Spring仅支持AspectJ切点指示器(pointcut designdator)的一个子集,Spring是基于代理的,而某些切点表达式与基于代理的AOP无关。下表仅列出Spring AOP支持的表达式

AspectJ指示器 描述
args() 限制连接点匹配参数为指定类型的执行方法,既能限制运行时入参参数类型,又能传递参数
@args() 限制连接点匹配参数由指定注解标注的执行方法
execution() 用于匹配是连接点的执行方法
this() 限制连接点匹配AOP代理的bean引用为指定类型的类,包括子类
target() 限制连接点匹配目标对象为指定类型的类,包括子类
@target() 限制连接点匹配的特定的执行对象,这些对象对应的类要有指定类型的注解
within() 限制连接点匹配指定的类型
@within() 限制连接点匹配指定注解所标注的类型
@annotation 限定匹配带有指定注解的连接点

bean():Spring引入的bean()指示器,使用Bean ID或name作为参数限制只匹配特定的bean

在Spring 尝试使用AspectJ其他指示器时,将会抛出IllegalArgument-Exception异常。

上述Spring支持的指示器中,只有execution是实际执行匹配的,而其他指示器都是用来限制匹配的。
说明exection指示器是我们编写切点定义时最主要使用的指示器。在此基础上,使用其他指示器限制匹配的切点。

编写切点

execution表达式语法:

execution(返回值类型 包名.类名.方法名(方法参数类型))

  1. 包.* 表示该层包下的类 包.*.* 该层子包下的类 以此类推(包.*.*.* 等)
  2. 包..*表示该层下所有类,包括子孙类

多指示器操作符

&&(and) 与关系
||(or) 或关系
!(not) 非关系

使用注解创建切面

AspectJ 5 引入关键特性 使用注解创建切面,在这之前,编写AspectJ切面需学习一种Java语言扩展。

@Aspect 声明切面
@Pointcut 声明切点,应在空方法上定义,通过 方法名() 调用
@Before 通知方法会在目标方法调用之前执行
@Around 通知方法会将目标方法封装起来
@AfterReturning 通知方法会在目标方法返回后调用
@AfterThrowing 通知方法会在目标方法抛出异常后调用
@After 通知方法会在目标方法返回或抛出异常后调用

在Java中开启切面

使用@Aspect声明切面,通过@Bean或@Compent将其注入Spring容器,并在配置类上使用@EnableAspectJAutoProxy开启自动代理功能。

在XML中开启切面

使用<bean>注入切面类,通过<aop:aspectj-autoproxy />开启自动代理功能。

注意,Spring的AspectJ自动代理仅仅使用@Aspect作为创建切面的指导,本质依然是SPring基于代理的切面。

这意味着,使用@Aspect注解,依然限于代理方法的调用。需利用AspectJ的所有能力,必须在运行时使用AspectJ并不依赖Spring创建切面。

Spring AOP实现引入功能

package cn;@Compentpublic class Perpon {    public void say() {        System.out.println("hello");    }}package cn;public Interface Reader {    void read();}package cn;public class ReaderImpl {    public void read() {        System.out.println("read《Spring In Action》");    }}@Aspectpublic class ReaderIntroducer {    @DeclareParents(value = "cn.demo",                    defaultImpl = ReaderImpl.class)    public Reader reader;}@Testpublic void test() {    Person person = ctx.getBean(person,Person.class);    person.say();    }

@DeclareParents 注解所标注的静态属性指明了要引入的接口,接口中声明了要引入的方法。

属性 说明
value 指定引入该接口的bean类型,(标示符后可添加'+'表示其所有子类型,而非其本身)
defaultImpl 指定为引入功能提供实现的类。

在XML中声明切面

基于注解的配置优于基于Java的配置,基于Java的配置优于基于XML的配置。

需要声明切面,但又不能为通知类添加注解时,只能转向XML配置(如事务管理切面等第三方通知)

Spring 的AOP配置能以非侵入性方式声明切面

AOP配置元素 用途
<aop:config> 顶层的AOP配置元素,大多数的<aop:*>必须包含在<aop:config>元素内
<aop:aspect> 定义一个切面
<aop:pointcut> 定义一个切点
<aop:advisor> 定义AOP通知器
<aop:before> 定义AOP前置通知
<aop:around> 定义AOP环绕通知
<aop:after-returning> 定义AOP返回通知
<aop:after-throwing> 定义AOP异常通知
<aop:after> 定义AOP后置通知(不管被通知的方法是否执行成功)
<aop:aspectj-autoproxy> 启用@Aspect注解的切面
<aop:declare-parents> 以透明的方式为被通知的对象引入额外的接口

注入AspectJ切面

package cn;public aspect AspectJDemo {    pointcut say() : execution(* say(..))        before() : say() { System.out.println("before"); }        after() : say() { System.out.println("after"); }        after()returning() : say() { System.out.println("after returning"); }        after()throwing() : say() { System.out.println("after throwing"); }        private String name;        public void setName(String name) {        this.name = name;    }}

具体请参考

Spring 注入AspectJ切面

1 Spring为AspectJ切面注入属性,需先将AspectJ切面声明为Spring bean;

2 AspectJ切面织入与Spring无关,其实例由AspectJ在运行期创建,而不能由Spring容器初始化;
3 所有AspectJ切面提供静态方法aspectOf(),返回AspectJ创建的切面实例;
4 Spring可通过工厂模式将AspectJ切面注入Spring容器,实现依赖注入。

转载地址:http://uohga.baihongyu.com/

你可能感兴趣的文章
【msdn wpf forum翻译】如何在wpf程序(程序激活时)中捕获所有的键盘输入,而不管哪个元素获得焦点?...
查看>>
全球首家!阿里云获GNTC2018 网络创新大奖 成唯一获奖云服务商
查看>>
Python简单HttpServer
查看>>
Java LinkedList工作原理及实现
查看>>
负载均衡SLB的基本使用
查看>>
Centos 7 x86 安装JDK
查看>>
微信小程序的组件用法与传统HTML5标签的区别
查看>>
Hangfire 使用笔记
查看>>
(C#)Windows Shell 外壳编程系列8 - 同后缀名不同图标?
查看>>
教你彻底学会c语言基础——文件操作
查看>>
如何使用免费控件将Word表格中的数据导入到Excel中
查看>>
seafile服务器配置
查看>>
HyperLedger Fabric 1.2 区块链应用场景(3.1)
查看>>
也谈谈初创公司的技术团队建设
查看>>
阿里云 APM 解决方案地图
查看>>
中国HBase技术社区第一届MeetUp-HBase2.0研讨圆桌会
查看>>
学渣的模块化之路——50行代码带你手写一个common.js规范
查看>>
python——变量
查看>>
subline上装node.js插件
查看>>
python字符串操作实方法大合集
查看>>