面向切面编程(AOP)的理解


Posted in Javascript onMay 01, 2015

在传统的编写业务逻辑处理代码时,我们通常会习惯性地做几件事情:日志记录、事务控制及权限控制等,然后才是编写核心的业务逻辑处理代码。当代码编写完成回头再看时,不禁发现,扬扬洒洒上百行代码中,真正用于核心业务逻辑处理才那么几行,如图6-4所示。方法复方法,类复类,就这样子带着无可奈何遗憾地度过了多少个春秋。这倒也罢,倘若到了项目的尾声,突然决定在权限控制上需要进行大的变动时,成千上万个方法又得一一"登门拜访",痛苦"雪上加霜"。

如果能把图6-4中众多方法中的所有共有代码全部抽取出来,放置到某个地方集中管理,然后在具体运行时,再由容器动态织入这些共有代码的话,最起码可以解决两个问题:

Java EE程序员在编写具体的业务逻辑处理方法时,只需关心核心的业务逻辑处理,既提高了工作效率,又使代码变更简洁优雅。

在日后的维护中由于业务逻辑代码与共有代码分开存放,而且共有代码是集中存放的,因此使维护工作变得简单轻松。

面向切面编程AOP技术就是为解决这个问题而诞生的,切面就是横切面,如图6-5所示,代表的是一个普遍存在的共有功能,例如,日志切面、权限切面及事务切面等。

下面我们以用户管理业务逻辑组件UserService的AOP实现过程(见图6-6)为例,深度剖析一下AOP技术的实现原理。AOP技术是建立在Java语言的反射机制与动态代理机制之上的。业务逻辑组件在运行过程中,AOP容器会动态创建一个代理对象供使用者调用,该代理对象已经按Java EE程序员的意图将切面成功切入到目标方法的连接点上,从而使切面的功能与业务逻辑的功能同时得以执行。从原理上讲,调用者直接调用的其实是AOP容器动态生成的代理对象,再由代理对象调用目标对象完成原始的业务逻辑处理,而代理对象则已经将切面与业务逻辑方法进行了合成。

现将图6-6中涉及到的一些概念解释如下。

切面(Aspect):其实就是共有功能的实现。如日志切面、权限切面、事务切面等。在实际应用中通常是一个存放共有功能实现的普通Java类,之所以能被AOP容器识别成切面,是在配置中指定的。

通知(Advice):是切面的具体实现。以目标方法为参照点,根据放置的地方不同,可分为前置通知(Before)、后置通知(AfterReturning)、异常通知(AfterThrowing)、最终通知(After)与环绕通知(Around)5种。在实际应用中通常是切面类中的一个方法,具体属于哪类通知,同样是在配置中指定的。

连接点(Joinpoint):就是程序在运行过程中能够插入切面的地点。例如,方法调用、异常抛出或字段修改等,但Spring只支持方法级的连接点。

切入点(Pointcut):用于定义通知应该切入到哪些连接点上。不同的通知通常需要切入到不同的连接点上,这种精准的匹配是由切入点的正则表达式来定义的。

目标对象(Target):就是那些即将切入切面的对象,也就是那些被通知的对象。这些对象中已经只剩下干干净净的核心业务逻辑代码了,所有的共有功能代码等待AOP容器的切入。

代理对象(Proxy):将通知应用到目标对象之后被动态创建的对象。可以简单地理解为,代理对象的功能等于目标对象的核心业务逻辑功能加上共有功能。代理对象对于使用者而言是透明的,是程序运行过程中的产物。

织入(Weaving):将切面应用到目标对象从而创建一个新的代理对象的过程。这个过程可以发生在编译期、类装载期及运行期,当然不同的发生点有着不同的前提条件。譬如发生在编译期的话,就要求有一个支持这种AOP实现的特殊编译器;发生在类装载期,就要求有一个支持AOP实现的特殊类装载器;只有发生在运行期,则可直接通过Java语言的反射机制与动态代理机制来动态实现。

以下是补充:

AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。

AOP与OOP是面向不同领域的两种设计思想。

OOP(面向对象编程)针对业务处理过程的实体及其属性和行为进行抽象封装,以获得更加清晰高效的逻辑单元划分。

AOP则是针对业务处理过程中的切面进行提取,它所面对的是处理过程中的某个步骤或阶段,以获得逻辑过程中各部分之间低耦合性的隔离效果。

我们可以单单从上面的字面上来理解AOP和OOP的话,用下面的理解也不为过:

OOP实际上是对对象的属性和行为的封装,而AOP对于这点就无从谈起,但是AOP是处理某个步骤和阶段的,从中进行切面的提取,也就是说,如果几个或更多个逻辑过程中,有重复的操作行为,AOP就可以提取出来,运用动态代理,实现程序功能的统一维护,这么说来可能太含蓄,如果说到权限判断,日志记录等,可能就明白了。如果我们单纯使用OOP,那么权限判断怎么办?在每个操作前都加入权限判断?日志记录怎么办?在每个方法里的开始、结束、异常的地方手动添加日志?所有,如果使用AOP就可以借助代理完成这些重复的操作,就能够在逻辑过程中,降低各部分之间的耦合了。二者扬长补短,互相结合最好。

下面详细了解一些AOP的概念:

•方面(Aspect):一个关注点的模块化,这个关注点实现可能另外横切多个对象。事务管理是J2EE应用中一个很好的横切关注点例子。方面用Spring的Advisor或拦截器实现。
•连接点(Joinpoint):程序执行过程中明确的点,如方法的调用或特定的异常被抛出。
•通知(Advice):在特定的连接点,AOP框架执行的动作。各种类型的通知包括“around”、“before”和“throws”通知。通知类型将在下面讨论。许多AOP框架包括Spring都是以拦截器做通知模型,维护一个“围绕”连接点的拦截器链。
•切入点(Pointcut):指定一个通知将被引发的一系列连接点的集合。AOP框架必须允许开发者指定切入点,例如,使用正则表达式。
•引入(Introduction):添加方法或字段到被通知的类。Spring允许引入新的接口到任何被通知的对象。例如,你可以使用一个引入使任何对象实现IsModified接口,来简化缓存。
•目标对象(Target Object):包含连接点的对象,也被称作被通知或被代理对象。
•AOP代理(AOP Proxy):AOP框架创建的对象,包含通知。在Spring中,AOP代理可以是JDK动态代理或CGLIB代理。
•编织(Weaving):组装方面来创建一个被通知对象。这可以在编译时完成(例如使用AspectJ编译器),也可以在运行时完成。Spring和其他纯Java AOP框架一样,在运行时完成织入。

Spring 中 AOP 代理由 Spring 的 IoC 容器负责生成、管理,其依赖关系也由 IoC 容器负责管理。至于Spring的AOP在项目中具体是怎么实现的,下篇博客会以日志记录为例进行学习。

Javascript 相关文章推荐
取得父标签
Nov 14 Javascript
一个js封装的不错的选项卡效果代码
Feb 15 Javascript
jQuery快速上手:写jQuery与直接写JS的区别详细解析
Aug 26 Javascript
JavaScript中常见获取元素的方法汇总
Mar 04 Javascript
值得分享的Bootstrap Table使用教程
Nov 23 Javascript
javascript监听页面刷新和页面关闭事件方法详解
Jan 09 Javascript
jQuery实现的简单拖动层示例
Feb 22 Javascript
JS时间控制实现动态效果的实例讲解
Jul 31 Javascript
es6+angular1.X+webpack 实现按路由功能打包项目的示例
Aug 16 Javascript
如何实现双向绑定mvvm的原理实现
May 28 Javascript
javascript绘制简单钟表效果
Apr 07 Javascript
js在HTML的三种引用方式详解
Aug 29 Javascript
yui3的AOP(面向切面编程)和OOP(面向对象编程)
May 01 #Javascript
使用AOP改善javascript代码
May 01 #Javascript
Javascript aop(面向切面编程)之around(环绕)分析
May 01 #Javascript
jQuery插件Zclip实现完美兼容个浏览器点击复制内容到剪贴板
Apr 30 #Javascript
jQuery插件slider实现拖动滑块选取价格范围
Apr 30 #Javascript
javascript实现验证身份证号的有效性并提示
Apr 30 #Javascript
PHP+jQuery实现随意拖动层并即时保存拖动位置
Apr 30 #Javascript
You might like
Body是什么,该怎么喝出咖啡里的口感
2021/03/03 咖啡文化
PHP+javascript液晶时钟
2006/10/09 PHP
PHP原生模板引擎 最简单的模板引擎
2012/04/25 PHP
PHP flock 文件锁详细介绍
2012/12/29 PHP
destoon调用自定义模板及样式的公告栏
2014/06/21 PHP
Laravel框架学习笔记(一)环境搭建
2014/10/15 PHP
PHP中读取文件的几个方法总结(推荐)
2016/06/03 PHP
浅谈PHP正则中的捕获组与非捕获组
2016/07/18 PHP
php操纵mysqli数据库的实现方法
2016/09/18 PHP
PHP fprintf()函数用法讲解
2019/02/16 PHP
拖动布局之保存布局页面cookies篇
2010/10/29 Javascript
现代 JavaScript 开发编程风格Idiomatic.js指南中文版
2014/05/28 Javascript
js正则表达式注册页面表单验证
2016/10/11 Javascript
JS判断输入的字符串是否是数字的方法(正则表达式)
2016/11/29 Javascript
关于axios不能使用Vue.use()浅析
2018/01/12 Javascript
vue2使用keep-alive缓存多层列表页的方法
2018/09/21 Javascript
代码整洁之道(重构)
2018/10/25 Javascript
浅谈Vue数据响应
2018/11/05 Javascript
详解钉钉小程序组件之自定义模态框(弹窗封装实现)
2020/03/07 Javascript
详解vue3.0 diff算法的使用(超详细)
2020/07/01 Javascript
[09:37]DOTA2卡尔工作室 英雄介绍圣堂刺客篇
2013/06/13 DOTA
[40:48]DOTA2上海特级锦标赛D组败者赛 Liquid VS COL第二局
2016/02/28 DOTA
python中使用PIL制作并验证图片验证码
2018/03/15 Python
python中字符串变二维数组的实例讲解
2018/04/03 Python
Python利用公共键如何对字典列表进行排序详解
2018/05/19 Python
nginx+uwsgi+django环境搭建的方法步骤
2019/11/25 Python
解决Django部署设置Debug=False时xadmin后台管理系统样式丢失
2020/04/07 Python
用Python实现职工信息管理系统
2020/12/30 Python
css3实现简单的白云飘动背景特效
2020/10/28 HTML / CSS
HTML5 Canvas自定义圆角矩形与虚线示例代码
2013/08/02 HTML / CSS
耐克中国官方商城:Nike中国
2018/10/18 全球购物
请用Java实现列出某个目录下的所有文件
2013/09/23 面试题
英语系毕业生自荐信
2013/10/31 职场文书
2014年应届大学生自我评价
2014/01/09 职场文书
船舶调度指挥系统——助力智慧海事
2022/02/18 无线电
「海贼王」112.9万粉丝纪念图标公布
2022/03/21 日漫