首页 > 代码库 > Spring之AOP
Spring之AOP
---------------siwuxie095
什么是 AOP
- AOP 的基本概念
AOP,即 Aspect Oriented Programming,面向切面编程,
通过 预编译方式 和 运行期动态代理 实现程序功能的统一维护
的一种技术
AOP 是一种比较新颖的设计思想,同时也是 Spring 框架中
一个非常重要的内容
AOP 将应用系统分为两个部分:
核心业务逻辑 以及 横向的通用逻辑,即 所谓的方面(切面)
如:所有大中型应用都要涉及到的持久化管理、事务管理、安全管理、
日志管理 以及 调试管理 …
在 Spring 中,提供了面向切面编程丰富的支持:
允许通过分离 应用的业务逻辑 与 系统级的服务,进行内聚性的开发。
应用对象只实现它们应该做的,即 完成业务逻辑,仅此而已。它们并
不负责,甚至不会意识到系统级别的关注点,如:日志 和 事务支持
- AOP 与 OOP 的关系
AOP 是对 OOP 面向对象编程的一种有益的补充,同时,AOP 也是 OOP 的延续
面向对象编程 OOP:
从静态角度考虑程序结构,即 OOP 对业务处理过程中的
实体以及属性和行为进行了抽象的封装,以获得更加清晰、
高效果的逻辑划分,研究的是一种静态的领域
面向切面编程 AOP:
从动态角度考虑程序运行过程,即 是针对业务处理过程中的
切面进行提取,它所面对的是处理过程中的某个步骤 或阶段,
研究的是一种动态的领域
- AOP 的主要功能
主要是用于系统级别的功能,如:日志记录、性能统计、
安全控制、事务处理、异常处理 …
- AOP 的主要意图
AOP 主要是将日志记录、性能统计、安全控制、事务处理、异常处理 等
代码从 业务逻辑代码 中划分出来
通过对这些行为的分离,希望可以将它们独立到 非指导性业务逻辑方法 中,
进而改变这些行为时,不影响 业务逻辑代码 的处理
即 AOP 把一些常用的服务进行模块化,并且用声明的方式将这些组件使用
到其他的业务组件中去
这样做的结果就是每一个业务组件只需要关心自己的业务逻辑,而不用去了解
一些常用的服务组件,保证了更高的内聚性
使用 AOP 可以将处理切面等代码注入程序,通常主程序的主要目的并不在于
处理这些切面的功能,所以 AOP 可以有效的防止代码混乱
Spring Framework 的 AOP 作为一种非侵略性的轻型的 AOP Framework,
无须使用预编译器,或其它元标签,便可以在 Java 程序中使用,这意味着开
发团队中只需要有一个人来应对 AOP Framework,其他人还可以像往常一样
进行业务逻辑的编程
AOP 的存在价值
AOP 专门用于处理系统中分布于各个模块中的交叉关注点的问题,
在 Java EE 应用中,常常通过 AOP 来处理一些具有横切性质的系
统级服务,如:事务管理、安全检查、缓存、对象池管理等,AOP
已经成为一种非常常用的解决方案
为什么要使用 AOP 呢?
是因为系统有很多不同的组件,每一个组件负责一块特定的功能,我们希望
每一个组件只关心它自身的核心功能,但在系统中会有一些组件,如:日志
模块、事务管理模块和安全模块 … 这些组件会比较频繁的融入到其他核心业
务逻辑组件当中去
这些常用组件分散到其他多个组件中,会带来麻烦:
(1)如果这些常用的服务组件经常发生变化,那么需要在多个
其他组件中进行相应地修改
(2)这样使得组件代码因为插入了与自身核心业务无关的服务
组件而变的很混乱
为了更好的说明为什么要使用 AOP,看如下实例:
如下图所示,假设系统中有三段完全相似的代码,这些代码通常使用
复制、粘贴的方式来完成。通过这种复制,粘贴方式所开发出来的软
件就像这幅图所描述的一样
它的不足之处是:如果有一天图中深色代码需要修改,就要打开三个地方
进行修改。那如果是一百个、一千个地方,后果可想而知 …
为了解决这个问题,通常会将深色代码定义为一个方法,然后在三个地方
分别调用该方法即可,在这种方式下,软件系统的结构如下图所示
对于上图所示的系统,如果需要修改深色代码,只要修改一个地方即可,
通过这种方式就大大降低了软件后期维护的复杂度
对于其中的三个方法,当前依然需要显式调用,这样做能够解决大部分
的应用场景
但对于一些更特殊的情况,应用需要三个方法彻底与深色方法相分离,
该如何解决呢?
因为软件需求变更是很频繁的事情,系统前期设计的三个方法,只实现了
核心业务的功能。过了一段时间,需要为三个方法增加事务控制,又过了
一段时间,客户提出三个方法需要用户合法性验证,只有合法用户才能执
行这些方法 …
面对这样的情况,该怎么办?通常有两种做法:
(1)根据需求说明书,直接拒绝客户要求
(2)拥抱需求,满足客户的需求
第一种做法显然不好,客户是上帝,应该尽量满足客户的需求。通常采用
第二种做法,那么如何解决?不可能每次都定义一个新的方法,然后修改
三个方法,增加新调用的方法,这样的工作量太大
希望有一种特殊的方法,只要定义了该方法,无需在三个方法中显式调用,
系统就会自动执行这些特殊的方法
上面的方法听起来很神奇,甚至有些不切实际,其实是完全可以实现的,
实现该需求的技术正是 AOP
AOP 的原理剖析
AOP 代理其实是由 AOP 框架动态生成的一个对象,该对象可作为目标对象使用
AOP 代理所包含的方法与目标对象的方法如下图所示:
AOP 实际上是由目标类的代理类实现的,AOP 代理其实是由 AOP 框架
动态生成的一个对象,该对象可以作为目标对象使用,AOP 代理包含了
目标对象的全部方法
但 AOP 代理的方法与目标对象的方法存在着差异:
AOP 方法在特定侵入点添加了增强处理,并回调了目标对象的方法
纵观 AOP 编程,其中程序员参与的只有三个部分:
(1)定义普通业务组件
(2)定义切入点:一个切入点可能会横切多个业务组件
(3)定义增强处理:增强处理就是在 AOP 框架为普通业务组件置入的处理动作
AOP 编程的关键:定义切入点 和 定义增强处理
一旦定义了合适的 切入点 和 增强处理,AOP 框架将会自动生成 AOP 代理
AOP 代理的方法有如下的公式:
代理对象的方法 = 增强处理 + 被代理对象的方法
在上面的业务定义中不难发现,Spring AOP 的实现原理其实很简单:
AOP 框架负责动态生成 AOP 代理类,这个代理类的方法则由 增强处理
和 回调目标对象的方法 组成
AOP 的关键概念
以下是官方文档所给出的 AOP 关键概念的解释:
(1)切面 - Aspect
切面是一个关注点的模块化,这个关注点可能会横切多个对象。事务
管理是 J2EE 应用中一个关于横切关注点的很好的例子
在 Spring 的 AOP 中,切面可以基于模式 或基于 Aspect 注解方式实现。
通俗的说:即 加入的切面类,如:通常所说的日志类
(2)连接点 - Join Point
连接点是在程序执行过程中的某个特定的点,
如:某方法调用的时候,或处理异常的时候
在 Spring 的 AOP 过程中,一个连接点总是表示一个
方法的执行。通俗的说:即 加入切点的那个点
(3)通知 - Advice
通知是在切面的某个特定连接点上所执行的动作,其中包括
around、before 和 after 等不同类型的通知
许多 AOP 的框架都是以拦截器作为通知模型,并且维护一个
以连接点为中心的拦截器链
(4)切入点 - Point Cut
切入点是匹配连接点的断言。通知和一个切入点表达式并联,
并在满足这个切入点的连接点上运行
切入点表达式如何和连接点匹配,是 AOP 的核心
Spring 缺省(默认)使用 AspectJ 切入点语法
(5)引入 - Introduction
引入是用来给一个类型声明额外的方法和属性
Spring 允许引入新的接口到任何被代理的对象,如:可以使用
引入来使一个 Bean 实现 isModify 的接口,以便简化缓存机制
(6)目标对象 - Target Object
目标对象就是被一个 或多个切面所通知的对象,
也被称作 被通知对象
既然 Spring AOP 是通过运行时代理实现的,
那么这个对象永远是一个被代理对象
(7)AOP 代理 - AOP Proxy
AOP 代理其实就是 AOP 框架创建的对象,用来实现切面契约
在 Spring 中,AOP 代理可以是 JDK 动态代理 或 CGLIB 代理
(8)织入 - Weaving
织入就是把切面连接到 其他应用程序类型 或对象之上,并
创建一个被通知的对象,这些可以在 编译的时候、类加载
的时候、或运行的时候 完成
Spring 和其他的纯 Java AOP 框架一样,在运行的时候来完成织入
AOP 的通俗理解
一个组件 A,不关心其他常用的服务组件 B,但组件 A 使用组件 B 时,
不是组件 A 自身去调用,而是通过配置等其他方式,如:Spring 中可
以通过 XML 配置文件
这样就使得组件 A 压根就不需要知道服务组件 B 是怎样的,爱存在不存在,
爱怎么存在都与组件 A 无关
A 只关心自己的业务逻辑,具体当 A 使用 B 时,都是通过配置文件去做,与 A 无关
【made by siwuxie095】
Spring之AOP