Aop学习笔记系列一
一、Aop解决了什么问题?
1、在说解决了什么问题之前,先介绍一些关键的知识点
a、功能需求:功能需求指项目中的增值需求,比如业务逻辑,UI,持久化(数据库)。
b、非功能需求:项目中次要的,但却不可缺少的元素,如日志记录,安全,性能和数据事务等等。
2、横切关注点
它是推动Aop发明的主要因素之一,横切关注点是应用与一个系统的多个部分的片段功能(相当于一个功能应用于系统的多个地方),横切关注点和非功能性需求有许多重叠:非功能性需求经常横切应用程序的多个部分。举例:如果有两个方法a和b,如果都要记录日志c,那么就必须在a和b中放置c,这里的c就是横切关注点。
ok,如果你清楚了上面的知识点,下面开始说Aop解决了什么问题。
在OOP项目中,有非常多的横切关注点分布在项目中,久而久之,这种交错的代码会变的越来越难开发和维护,这是OOP技术不能捕获和解决的问题所以Kiczales和他的团队提出了Aop的概念,并将其作为OOP的一种补充,即使用"切面aspects"封装横切关注点以及允许重复使用。最终实现了AspectJ,就是今天Java开发者仍然使用的一流AOP工具。AOP官方文档
3、切面的任务:通知(Advice)
如果你理解了2的横切关注点,那么通知就是执行横切关注点的代码,比如对于横切关注点-日志功能,那么通知可能是log4net或者其他日志库的调用代码。
4、切面的映射:切入点(PointCut)
切入点就相当于在哪里放置通知(advice)的代码,也就是在哪里放置执行横切关注点的代码,下面通过一行代码来解释:
- dataService.AddRecord();//dataService是DataService的实例
当确认了一个连接点和一个通知,就可以定义切面了。切面通过叫做组合(weaving)的过程工作。
5、Aop开始组合(weaving)
5.1、 在没有Aop的时候,有两点你需要知道
a、缠绕(tangling),系统的核心业务逻辑往往是和横切关注点缠绕在一起的.代码如下:
- class Moudle
- {
- //日志成员
- public void Method()
- {
- //日志记录开始
- //核心代码
- //日志记录结束
- }
- }
上面这个过程就是缠绕,横切关注点日志功能,和核心代码缠绕在一起
b、分散,当横切关注点用于多个方法和多个类时,代码分散在整个应用中.代码如下:
- class Moudle
- {
- //日志成员
- public void Method()
- {
- //日志记录开始
- //核心代码
- //日志记录结束
- }
- }
- class Moudle1
- {
- //日志成员
- public void Method()
- {
- //日志记录开始
- //核心代码
- //日志记录结束
- }
- }
当横切关注点出现在了两个及以上的类或者方法中,这种形式就叫做分散,因为代码分散在整个应用中。
c、违反"单一职责"原则,一个类应该只有一个要修改的理由,不能因为类中参杂着的横切关注点的变化,而去修改他,这样的类设计是不合理的.
d、反模式:反模式是软件工程已确认的一种模式,例如你可以在“Gang of Four book”(全名是:设计模式:可复用面向对象软件的基础)中找到任何模式,跟那些好的模式不同,反模式会导致bug,产生昂贵的维护费用以及令人头疼的问题。
e、横切关注点的增多,如果你不及时采用DI或者装饰着模式或者Aop,那么你就会一直的处于复制黏贴的状态,从而违反了Don't Repeat yourself(DRY)原则!
5.2、解决方案
通过DI(依赖注入),代码如下:
- class Moudle
- {
- //_核心成员
- //_日志成员
- public Moudle(//日志接口 成员) 这里将日志接口通过DI注入进来
- {
- //this._日志成员=成员;
- }
- public void Method()
- {
- //_日志成员.日志记录开始
- //核心代码
- //_日志成员.日志记录结束
- }
- }
通过代码发现,即使使用了依赖注入,代码仍然是缠绕的。
通过通过DI(依赖注入)+装饰者,代码如下:
- class MoudleDecorator
- {
- //_realmoudle
- //_日志成员
- public MoudleDecorator(//Moudle moudle,日志接口 成员) 这里将日志接口通过DI注入进来
- {
- //this._realmoudle=moudle;
- //this._日志成员=成员;
- }
- public void Method()
- {
- //_日志成员.日志记录开始
- //moudle.Method();
- //_日志成员.日志记录结束
- }
- }
- class Moudle
- {
- public void Method()
- {
- //核心代码
- }
- }
ok,我们发现装饰着能很好的解决问题,但是如果这种装饰类一多,这个代码量好像又上去了,所以又开始重复造轮子了,所以当超过3个装饰者的时候,就可以考虑改用Aop的切面了。
so,终极方案Aop登场,先看图
Aop就是为了解决上面的问题,下面使用Aop对上面的代码进行重构
代码如下:
- class Moudle
- {
- //[LoggingAspect]
- public void Method()
- {
- //核心代码
- }
- }
- class LoggingAspect
- {
- //_日志成员
- public void LoggingAspect(//日志接口 成员) 通过依赖注入
- {
- //this._日志成员=成员;
- }
- void OnEntry()
- {
- //日志记录开始
- }
- void OnSuccess()
- {
- //日志记录结束
- }
- }
通过Aop重构之后的代码更易于管理,更不容易出bug,如果你的Aop工具类库是稳定的话,代码的可读性也更强,更容易维护,降低维护的开销,如果使用Aop重构代码将横切关注点单独封装到一个切面类中,你就不用到处修改代码,只需要在一个类中修改就可以了。
下面是一个伪代码类,由于横切关注点而没有遵守单一职责原则:
- public class AddressBookService
- {
- public string GetPhoneNumber( string name )
- {
- if ( name is null )
- throw new ArgumentException( "name" );
- var entry = PhoneNumberDatabase.GetEntryByName( name );
- return(entry.PhoneNumber);
- }
- }
虽然上面的代码阅读和维护都相当简单,但是它做了两件事:一是检查传入的name是否是有效的;二是基于传入的name找到电话号码。虽然检查参数的有效性和服务方法相关,但是它仍然是可以分离和复用的辅助功能。下面是使用AOP重构之后的伪代码:
- public class AddressBookService
- {
- [CheckForNullArgumentsAspect]
- public string GetPhoneNumber( string name )
- {
- var entry = PhoneNumberDatabase.GetEntryByName( name );
- return(entry.PhoneNumber);
- }
- }
- public class CheckForNullArgumentsAspect
- {
- public void OnEntry( MethodInformation method )
- {
- foreach ( arg in method.Arguments )
- if ( arg is null )
- throw ArgumentException( arg.name )
- }
- }
这个例子中的OnEntry
方法多了个MethodInformation
参数,它提供了一些关于方法的信息,为的是可以检测方法的参数是否为null。虽然这个方法微不足道,但是CheckForNullArgumentsAspect
代码可以复用到确保参数有效的其他方法上。
- public class AddressBookService
- {
- [CheckForNullArgumentAspect]
- public string GetPhoneNumber( string name )
- {
- ...
- }
- }
- public class InvoiceService
- {
- [CheckForNullArgumentAspect]
- public Invoice GetInvoiceByName( string name )
- {
- ...
- }
- [CheckForNullArgumentAspect]
- public void CreateInvoice( ShoppingCart cart )
- {
- ...
- }
- }
- public class PaymentSevice
- {
- [CheckForNullArgumentAspect]
- public Payment FindPaymentByInvoice( string invoiceId )
- {
- ...
- }
- }
这样一来,如果我们想要修改和Invoice相关的东西,只需要修改InvoiceService
。如果想要修改和null检测相关的一些事情,只需要修改CheckForNullArgumentAspect
。涉及到的每个类只有一个原因修改。现在我们就不太可能因为修改造成bug或倒退。
Aop学习笔记系列一的更多相关文章
- MongoDB学习笔记系列
回到占占推荐博客索引 该来的总会来的,Ef,Redis,MVC甚至Sqlserver都有了自己的系列,MongoDB没有理由不去整理一下,这个系列都是平时在项目开发时总结出来的,希望可以为各位一些帮助 ...
- Dynamic CRM 2013学习笔记 系列汇总
这里列出所有 Dynamic CRM 2013学习笔记 系列文章,方便大家查阅.有任何建议.意见.需要,欢迎大家提交评论一起讨论. 本文原文地址: Dynamic CRM 2013学习笔记 系列汇总 ...
- SQLServer学习笔记系列3
一.写在前面的话 今天又是双休啦!生活依然再继续,当你停下来的时候,或许会突然显得不自在.有时候,看到一种东西,你会发现原来在这个社会上,优秀的人很多,默默 吃苦努力奋斗的人也多!星期五早上按时上班, ...
- SQLServer学习笔记系列2
一.写在前面的话 继上一次SQLServer学习笔记系列1http://www.cnblogs.com/liupeng61624/p/4354983.html以后,继续学习Sqlserver,一步一步 ...
- Dynamic CRM 2015学习笔记 系列汇总
这里列出所有 Dynamic CRM 2015学习笔记 系列文章,方便大家查阅.有任何建议.意见.需要,欢迎大家提交评论一起讨论. 本文原文地址:Dynamic CRM 2015学习笔记 系列汇总 一 ...
- 步步为营 SharePoint 开发学习笔记系列总结
转:http://www.cnblogs.com/springyangwc/archive/2011/08/03/2126763.html 概要 为时20多天的sharepoint开发学习笔记系列终于 ...
- WebService学习笔记系列(二)
soap(简单对象访问协议),它是在http基础之上传递xml格式数据的协议.soap协议分为两个版本,soap1.1和soap1.2. 在学习webservice时我们有一个必备工具叫做tcpmon ...
- .NET CORE学习笔记系列(2)——依赖注入[7]: .NET Core DI框架[服务注册]
原文https://www.cnblogs.com/artech/p/net-core-di-07.html 包含服务注册信息的IServiceCollection对象最终被用来创建作为DI容器的IS ...
- .NET CORE学习笔记系列(2)——依赖注入[6]: .NET Core DI框架[编程体验]
原文https://www.cnblogs.com/artech/p/net-core-di-06.html 毫不夸张地说,整个ASP.NET Core框架是建立在一个依赖注入框架之上的,它在应用启动 ...
随机推荐
- com.liuyang.exception.DaoException: java.sql.SQLException: Incorrect string
错误是在JUnit测试的时候产生的,但是实际加入数据也会产生这样的情况,主要是数据库内部的编码方式不支持当前的编码方式导致的冲突,解决方法就是在建立数据库之前,要查看当前的数据库的编码方式,方法和更改 ...
- 解决Error creating bean with name 'huayuanjingguanDaoimp' defined in file [D:\apache-tomcat-7.0.52\webapps\landscapings\WEB-INF\classes\com\itheima\landscaping\dao\imp\huayuanjingguanDaoimp.class]: Invo
问题描述: 10:23:13,585 ERROR ContextLoader:307 - Context initialization failedorg.springframework.beans. ...
- C++中的矩阵运算
C++中的矩阵运算 1. 2阶矩阵的逆矩阵公式
- java中如何通过Class获取类的属性、方法、注释
public static String getPKName(Class clazz) { Field[] fields = clazz.getDeclaredFields(); for (Field ...
- maven下@override标签失效
经常遇见此问题,现记录如下,以备下次查阅. 在pom文件添加配置: <plugin> <groupId>org.apache.maven.plugins</groupId ...
- EBS获取附件URL
http://wenku.baidu.com/link?url=MnYX269RBqW9ZRh-4famwduhYq9As0-vsIyVPA7aqv64cdxxjZEOaEE1_KZ9SGjY9qCx ...
- Windows 8/8.1 及 Windows Phone 8 应用神器 - APP Producer
继 App studio 以及 Project Siena 之后 微软再次打造应用生成器 APP Producer,这个版本的应用生成器功能相对比之前两个版本要简单许多,更适合入门并且真正的支持全平 ...
- 手动处理TFS数据仓库服务和分析服务
当您需要报告中最新的数据时,当发生错误时,或者在解决了模式冲突之后,您可以手动处理Team Foundation Server(TFS)关系数据库(TFSHStor)或SQLServer Analys ...
- LINQ to objects遇到的小坑
1.C#中LINQ to Objects中延迟查询的陷阱(其他类型的LINQ也基本一致) 之前在不了解LINQ延迟查询的时候,我使用下面的这种方式,将where语句的结果直接as为List<T& ...
- ueditor图片上传插件的使用
在项目里使用到ueditor图片上传插件,以前图片上传都是直接使用js代码直接上传图片,比较麻烦,而且效率也比较低,而ueditor这款插件完美的解决了这个问题,这个是百度开发的一款富文本编辑器,在这 ...