Spring AOP 的简单应用

因为工作需求,自己去了解一下aop并做下的记录,当然大部分都是参考他人博客以及官方文档。

目录

<a name="关于 AOP"></a>

关于 AOP

大家都知道Spring框架有两大重要特性,IOC 控制反转 (Inversion of Control,IoC) 以及AOP 面向切面编程(Aspect Oriented Program, AOP)。今天主要是来一起了解一下AOP。

其主要作用是,在不修改源代码的情况下给某个或者一组操作添加额外的功能。像日志记录,事务处理,权限控制等功能,都可以用AOP来“优雅”地实现,使这些额外功能和真正的业务逻辑分离开来,软件的结构将更加清晰。

简单来说在运行时,动态地将代码切入到类的指定方法、指定位置上的编程思想就是面向切面的编程。

<a name = "相关术语"></a>

相关术语

Aspect(切面)

aspectpointcutadvice组成,它即包含了横切的定义,也包含了链接点的定义。由Spring AOP负责实施切面,它将切面所定义的横切逻辑织入到切面所指定的链接点中。

简单来说,只要在类上有 @Aspect 注解的类就是切面。

Join point(链接点/记录点)

程序运行中的一个点,例如一个运行方法或者异常处理。

在Spring AOP中,一个join point总是一个运行方法,即只有方法才是连接点。

advice (增强/通知)

在join point(即满足 point cut 规则的join point)上特定的时刻执行的操作,Advice有几种不同类型,下文将会讨论(通俗地来讲就是起作用的内容和时间点)。

Pointcut(切点)

匹配 join point 的谓词(a predicate that matches join points).

advice 与 pointcut 表达式相关联,并在与 pointcut 匹配的任意 joinpoint 运行(例如,执行具有特定名称的方法)。

简单来说 pointcut 是一个joinpoint 的过滤器,只有满足 pointcut 的规则的 joinpoint 才会执行 advice。

Introduction

为一个类型添加额外的方法或字段. Spring AOP 允许我们为 目标对象 引入新的接口(和对应的实现). 例如我们可以使用 introduction 来为一个 bean 实现 IsModified 接口, 并以此来简化 caching 的实现.

Target object

织入一个或多个 advice 的目标对象. 目标对象也被称为 advised object.

因为 Spring AOP 使用运行时代理的方式来实现 aspect, 因此 adviced object 总是一个代理对象(proxied object)
注意, adviced object 指的不是原来的类, 而是织入 advice 后所产生的代理类.

AOP proxy

一个类被 AOP 织入 advice, 就会产生一个结果类, 它是融合了原类和增强逻辑的代理类.在 Spring AOP 中, AOP 代理将是一个 JDK 动态代理对象或 CGLIB 代理对象.

Weaving (织入)

将 aspect 和其他对象连接起来, 并创建 adviced object 的过程.根据不同的实现技术, AOP织入有三种方式:

  • 编译器织入, 这要求有特殊的Java编译器.
  • 类装载期织入, 这需要有特殊的类装载器.
  • 动态代理织入, 在运行期为目标类添加增强(Advice)生成子类的方式.

与其他纯Java AOP框架一样,Spring AOP在运行时执行编织。

advice 的类型

  • before advice, 在 join point 前被执行的 advice. 虽然 before advice 是在 join point 前被执行, 但是它并不能够阻止 join point 的执行, 除非发生了异常(即我们在 before advice 代码中, 不能人为地决定是否继续执行 join point 中的代码)
  • after return advice, 在一个 join point 正常返回后执行的 advice
  • after throwing advice, 当一个 join point 抛出异常后执行的 advice
  • after(final) advice, 无论一个 join point 是正常退出还是发生了异常, 都会被执行的 advice.
  • around advice, 在 join point 前和 joint point 退出后都执行的 advice. 这个是最常用的 advice.

Pointcut expression

Pointcut通过pointcut expression来描述,有若干种限定词。具体可以参考Spring文档7.2.3 Declaring a pointcutaspectj-cheat-sheet.

<a name="Spring AOP的使用"></a>

Spring AOP的使用

我们可以通过三种方式来使用Spring AOP,他们分别是:@Aspect-based(Annotation),Schema-based(XML),以及底层的Spring AOP API。我们后续讲解的主要是基于注解的实现。

使用xml的实现原理与使用注解基本一致,基本上只是把注解包含的配置信息都转移到了xml配置文件中。

至于AOP API则是Spring1.2提供的历史用法,现在的Sping4也仍然支持,注解与xml也是基于其上的使用。它是SpringAOP的基础,有兴趣的可以去参考链接4查看。

<a name="基于注解的使用"></a>

基于注解的使用

添加 @AspectJ 支持

@AspectJ 是一种使用 Java 注解来实现 AOP 的编码风格.
@AspectJ 风格的 AOP 是 AspectJ Project 在 AspectJ 5 中引入的, 并且 Spring 也支持@AspectJ 的 AOP 风格.

<a name="添加依赖"></a>

添加依赖

 <!-- 5)Spring AOP -->
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>${spring.version}</version>
  </dependency>
  <!-- aspectj依赖开始 -->
  <dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjrt</artifactId>
    <version>${aspectj.version}</version>
  </dependency>
  <dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>${aspectj.version}</version>
  </dependency>
  <!-- aspectj依赖结束 -->

<a name="开启 @Aspect 注解"></a>

开启 @Aspect 注解

    在 spring-mvc.xml 中添加一下语句 用于启用@Aspect注解
    <aop:aspectj-autoproxy/> //jdk 代理
    或
    <aop:aspectj-autoproxy proxy-target-class="true" /> //cglib 代理

    
    并且需要在xml中加上 aop 的 namespace
    <?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 definitions here -->

    </beans>

jdk 代理 与 CGlib 代理
JDK动态代理只能对实现了接口的类生成代理,而不能针对类 。
CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的 方法 。
因为是继承,所以该类或方法最好不要声明成final ,final可以阻止继承和多态。

<a name="定义 aspect(切面)"></a>

定义 aspect(切面)

当使用注解 @Aspect 标注一个 Bean 后, 那么 Spring 框架会自动收集这些 Bean, 并添加到 Spring AOP 中, 例如:

@Aspect
@Component
public class TestAspect {
}

请注意,@Aspect 不能被 Spring 自动识别并注册为 Bean;为此,您需要添加一个单独的 @Component 注释

<a name="声明 pointcut"></a>

声明 pointcut

pointcut 声明由两部分组成:

Pointcut签名(signature) 包括方法名和相关参数

Pointcut表示式(expression) 用来指定哪些方法执行是我们感兴趣的(即因此可以织入 advice).


pointcut expression
pointcut expression

这个方法必须无返回值.
这个方法本身就是 pointcut signature, pointcut 表达式使用@Pointcut 注解指定.
上图定义了一个 pointcut,它所描述的是:匹配在项目路径 aspects.trace.demo 下的所有方法的执行

<a name="切点标志符"></a>

切点标志符(designator)

具体使用请参考案例代码

  • execution - for matching method execution join points, this is the primary pointcut designator you will use when working with Spring AOP
  • within - limits matching to join points within certain types (simply the execution of a method declared within a matching type when using Spring AOP)
  • this - limits matching to join points (the execution of methods when using Spring AOP) where the bean reference (Spring AOP proxy) is an instance of the given type
  • target - limits matching to join points (the execution of methods when using Spring AOP) where the target object (application object being proxied) is an instance of the given type
  • args - limits matching to join points (the execution of methods when using Spring AOP) where the arguments are instances of the given types
  • bean - limit the matching of join points to a particular named Spring bean, or to a set of named Spring beans (when using wildcards).
  • @target - limits matching to join points (the execution of methods when using Spring AOP) where the class of the executing object has an annotation of the given type
  • @args - limits matching to join points (the execution of methods when using Spring AOP) where the runtime type of the actual arguments passed have annotations of the given type(s)
  • @within - limits matching to join points within types that have the given annotation (the execution of methods declared in types with the given annotation when using Spring AOP)
  • @annotation - limits matching to join points where the subject of the join point (method being executed in Spring AOP) has the given annotation

<a name="声明 advice"></a>

声明 advice

advice 是和一个 pointcut 表达式关联在一起的, 并且会在匹配的 join point 的方法执行的前/后/周围 运行. pointcut 表达式可以是简单的一个 pointcut 名字的引用, 或者是完整的 pointcut 表达式.

* Before

 Before Advice 由切面中的 @Before 注解声明

 代表 advice 在 joinpoint 之前执行
* After returning

 当匹配的方法正常执行并返回时运行 After returning Advice。

 由 @AfterReturning 注解声明

* After throwing 
 当匹配的方法执行并抛出异常退出时,运行。
 
 由 @AfterThorwing 注解声明。

* After (finally)
 当匹配的方法执行完成并退出后执行。
 
 通过 @After 声明
 
        try{
            try{
                //@Before
                method.invoke(..);
            }finally{
                //@After
            }
            //@AfterReturning
        }catch(){
            //@AfterThrowing
        }

* Around
 它可以在一个方法的之前之前和之后添加不同的操作, 并且甚至可以决定何时, 如何, 是否调用匹配到的方法.
 
 通过 @Around 声明  

<a name = "代码地址">

代码地址

https://github.com/Kcyfrank/SpringMVC-example

<a name = "参考链接">

参考链接:

  1. 官方文档 Aspect Oriented Programming with Spring
  2. 彻底征服 Spring AOP 之 理论篇
  3. aspectj-cheat-sheet
    <a name = "参考4">
  4. Spring AOP API介绍
  5. spring-aop-target-vs-this
  6. Spring 之AOP AspectJ切入点语法详解(最全了,不需要再去其他地找了)
  7. AOP 那点事儿 & 续
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 151,688评论 1 330
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 64,559评论 1 273
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 101,749评论 0 226
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 42,581评论 0 191
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 50,741评论 3 271
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 39,684评论 1 192
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,122评论 2 292
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 29,847评论 0 182
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,441评论 0 228
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 29,939评论 2 232
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,333评论 1 242
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 27,783评论 2 236
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,275评论 3 220
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,830评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,444评论 0 180
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 34,553评论 2 249
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 34,618评论 2 249

推荐阅读更多精彩内容

  • 基本知识 其实, 接触了这么久的 AOP, 我感觉, AOP 给人难以理解的一个关键点是它的概念比较多, 而且坑爹...
    永顺阅读 7,808评论 5 114
  • **2014真题Directions:Read the following text. Choose the be...
    又是夜半惊坐起阅读 8,433评论 0 23
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,050评论 18 139
  • What? As we all know,在进行项目构建时,追求各模块高内聚,模块间低耦合。然而现实并不总是如此美...
    MasterNeo阅读 1,877评论 0 17
  • 几番冷雨过后春风荡漾不息拂过山岗湖泊听过无数故事后在这如水的夜里穿过万水和千山 我遥望北方灯火心上的人可无恙你也知...
    茶石阅读 328评论 0 2