AOP 你想干什么 IOC 你服务什么

Wesley13
• 阅读 650

前言:

记得N年前,就听过AOP,曾扫过几篇文章,不过看不懂,还是N年前,面试被问到AOP的切面,还是不懂!

中秋之假,有点闲,在博客园里搜了下AOP看了看,试图看懂些许文章,可惜文章都说的太中规中矩,没发现一篇能浅显看的易懂的。

AOP,全称Aspect Oriented Programming,中文名称叫面向方面编程,也叫面向切面编程。

AOP,你出来的意图?

借用一图:

AOP 你想干什么 IOC 你服务什么

不就为解耦,分离出权限/操作日志/异常/事务等模块出来?

这里贴一段我项目中的代码,最常见的修改密码:

AOP 你想干什么 IOC 你服务什么 AOP 你想干什么 IOC 你服务什么

protected void  Page_Load( object  sender, EventArgs e)
        {
             if  ( ! Page.IsPostBack)
            {
                SetPermission(SysModule.修改密码).HasUpdatePermission();
                lblUser.Text  =  CurrentUser.User_Name;
            }
        }
         protected void  btnOK_Click( object  sender, EventArgs e)
        {
             if  (CurrentUser.Password  ==  tbxPassword.Text)
            {
                UserListBean entity  = new  UserListBean();
                entity.ID  =  CurrentUser.ID.Value;
                entity.Password  =  tbxPwdNew.Text;
                 if  (Factory < UserListBean > .Instance.Update(entity))
                {
                    LogWrite.Write(LogModule.用户管理, LogType.编辑,  string .Format( " 修改密码[用户名称={0}] " , CurrentUser.User_Name));
                    CommonHelper.ShowDoneMessage();
                }
            }
            Show( " 旧密码错误! " ,Request.RawUrl);
        }

问题说明:

几乎每个页面在PageLoad都有权限判断语句;在更新成功时,都会有操作日志记录,非常之常见。

**AOP想让我们干什么?就是让我们,不要在每个页面都这样写权限判断和日志操作了。
**

不让我这样写,那咋写?AOP你让我咋写呢?

AOP说:

你可以独立实现权限/操作日志等模块,然后使用动态拦截调用的方法,

在方法调用之前,你先调用[Begin]函数实现权限判断;

在方法调用之后,再调用[End]函数来写日志.

那咋整呢?

AOP说:

这个,两种方式

说起来有点复杂,借用别人的话说一下好了:

AOP 你想干什么 IOC 你服务什么 AOP 你想干什么 IOC 你服务什么

目前在.Net下实现AOP的方式分为两大类:

一是采用动态代理技术,利用截取消息的方式,对该消息进行装饰,以取代或修饰原有对象行为的执行;

二是采用静态织入的方式,引入特定的语法创建“方面”,从而使得编译器可以在编译期间织入有关“方面”的代码。

动态代理实现方式利用.Net的Attribute和.Net Remoting的代理技术,对对象执行期间的上下文消息进行截取,并以消息传递的方式执行,从而可以在执行期间加入相关处理逻辑实现面向方面的功能(请参考:http: //www.cnblogs.com/wayfarer/articles/256909.html);

而静态织入的方式实现一般是要依靠一些第三方框架提供特定的语法,例如PostSharp,它的实现方式是采用 MSIL Injection和MSBuild Task在编译时置入方面的代码,从而实现AOP。

说白一点:

在一些类和方法上面标属性,然后继承特定接口或类,之后便可进行消息拦截,拦截后还是根据属性来调用其它方法

有源码呢:

我这里有一份动代代理实现拦截的代码,可点击下载

看完源码我说说:

我本来就两行代码,一行权限,一行操作日志,
为了解耦,你弄了一堆鬼都看不懂的代码,好吧,算是能正常运行,可是这咋应用上?
权限的类型我到哪传?操作日志的类型,操作的用户名称,我去哪拿去?你说,唉,越来越复杂了!
还有,大伙到处说你性能低呢,还有你解耦还有不就为了维护方便么,可是你那一堆鬼都难看懂的代码,要是换另一个人来维护,那不是天天要叫太阳。

AOP说:

我的想法很好的,让你分离下权限/操作日志,独立出去统一管理,以后改代码不用跑每个页面改去。

至于实现,是相对复杂了点,为能了拦截每个方法的调用,在调用的前后插入其它方法,得底层一点,所以不平易近人了。

要简单实现,你们还是找IOC好了,它简单一些。

IOC:英文为 Inversion of Control,即反转模式又称DI:Dependency Injection,即依赖注入

IOC说:

我可不像AOP那些实现一样,能动态拦截方法,遍历标志的属性再执行相应的方法那么强大而复杂。

其实我很简单,就是在类里随便挖个洞,能让我钻进去就行了。

来个简单示例

一个接口:

public interface  IAop
    {
         void  Begin();
         void  End();
    }

注入到人家的构造函数里:

AOP 你想干什么 IOC 你服务什么 AOP 你想干什么 IOC 你服务什么

public class  MAction
    {
        IAop _Aop;
         public  MAction(IAop aop)
        {
            _Aop  =  aop;
        }
         public void  Add()
        {
            _Aop.Begin();
            Console.WriteLine(" http://cyq1162.cnblogs.com/ ");
            _Aop.End();
        }
    }

看看

现在如果你调用Add,是不是就要先执行Begin方法,执行完内容之后,又要执行End方法了。

接下来,实现接口:

AOP 你想干什么 IOC 你服务什么 AOP 你想干什么 IOC 你服务什么

public class  AopAction:IAop
    {
         #region  IAop 成员 public void  Begin()
        {

//其实我是很茫然的,我不知道我应该干什么,我被很多方法调用,可是,我咋知道是谁调用我呢?我要怎么写分支语句呢?啥都没,只好输出begin...
            Console.WriteLine( " begin...... " );
        }

         public void  End()
        {

//同样我也很困惑,我是在人家操作完后调用的,我都不知你是更新/删除/插入还是其它,或者写日志你得给我个ID啊,啥都没,我只能输出end....
            Console.WriteLine( " end...... " );
        }

         #endregion }

最后调用:

MAction action  = new  MAction( new  AopAction());
action.Add();

结果当然是:

begin......
http://cyq1162.cnblogs.com/

end......

当然了,IOC强大的东西不仅仅只是在构造函数注入了,不过在哪注入,还是通过反射注入,都不是本节的重点,也不是现在关注的问题。

现在的问题是:

我上面的代码要咋整改呢?说了一堆,应用不上,不白说了?

好吧,说正事了,咋改呢?

其实数据库操作不外乎增删改查了。只要在增删改查上做足功夫,基本上应用是没问题了,复杂的应用就另外找大仙去吧。

我们只要在每个Insert/Update/Delete/Select的方法之前与之后插入Begin与End函数,同样使用IOC注入,即可,方法不多吧。

分析下:

比如上面的权限,说到底内部还是调用select来决定有没有权限;

上面的操作日志,也就是Update后的事情;

所以,具体代码怎么改,不同的框架实现改起来是不同了。

还有最重要的是,统一管理后,你怎么传参获到分类与更新后的用户名称。

说白了Begin和End函数,你得给点参数,不然叫人家方法写啥呢?

难道页面放个隐藏域,再Request一下或取当前Url来判断分支与使用?是个方法,不过有点悬!!!

举例说明使用:这里使用 CYQ.Data 框架 来说明

1:定义操作枚举

AOP 你想干什么 IOC 你服务什么 AOP 你想干什么 IOC 你服务什么

public enum  AopEnum
    {
        Select,
        Insert,
        Update,
        Delete,
        Fill,
        GetCount,
        ExeMDataTable,
        ExeNonQuery,
        ExeScalar
    }

2:定义IAop接口

AOP 你想干什么 IOC 你服务什么 AOP 你想干什么 IOC 你服务什么

public interface  IAop
    {
         void  Begin(AopEnum action, string  objName,  params object [] aopInfo);
         void  End(AopEnum action,  bool  success,  object  id,  params object [] aopInfo);
         void  OnError( string  msg);
    }

3:预先实现

AOP 你想干什么 IOC 你服务什么 AOP 你想干什么 IOC 你服务什么

internal class  Aop:IAop
{
    #region  IAop 成员 public void  Begin(AopEnum action,  string  objName,  params object [] aopInfo){}
     public void  End(AopEnum action,  bool  success,  object  id,  params object [] aopInfo){}
     public void  OnError( string  msg){}
     #endregion
}

*4:内部用Setter方式开个洞,不使用构造函数注入,方法里增加Begin调用与End调用*

AOP 你想干什么 IOC 你服务什么 AOP 你想干什么 IOC 你服务什么

public class  MAction : IDisposable
    {
         private  Aop.IAop _Aop = new  Aop.Aop(); // 切入点
public void  SetAop(Aop.IAop aop)
        {
            _Aop  =  aop;
        }
         public bool  Fill( object where ,  params object [] aopInfo)
        {
            _Aop.Begin(Aop.AopEnum.Fill,_TableName, aopInfo);

             bool  result  =  操作结果

            _Aop.End(Aop.AopEnum.Fill, result, aopInfo);
             return  result;
        }
     }

说明:

使用预先实现,可以不用判断_Aop是不是为null

不使用构造函数实现注入,是为了使用继承来一次性使用SetAop,从而避免到处使用SetAop

框架的代码基本就到此结束,那如何使用框架呢?

1:继承IAop接口,如

AOP 你想干什么 IOC 你服务什么 AOP 你想干什么 IOC 你服务什么 接口实现统一管理处

///


///  作者:路过秋天
///  博客: http://cyq1162.cnblogs.com
///

public class  MyAop:CYQ.Data.Aop.IAop
{

     #region  IAop 成员 public void  Begin(CYQ.Data.Aop.AopEnum action,  string  objName,  params object [] aopInfo)
    {
         switch  (action)
        {
             case  CYQ.Data.Aop.AopEnum.Select:
                HttpContext.Current.Response.Write( string .Format( " Begin方法:权限判断执行:[{0}表查询]
" ,objName));
                 break ;
        }
    }

     public void  End(CYQ.Data.Aop.AopEnum action,  bool  success,  object  id,  params object [] aopInfo)
    {
         switch  (action)
        {
             case  CYQ.Data.Aop.AopEnum.GetCount:
                 if  (aopInfo.Length  > )
                {
                     switch  (aopInfo[ ].ToString())
                    {
                         case " Login " :
                            HttpContext.Current.Response.Write( " End  方法:操作日志:登陆结果: " +  (success  ? " 成功 "  :  " 失败 " )  + "
" );
                             break ;
                    }
                }
                 break ;
        }
    }

     public void  OnError( string  msg)
    {
         throw new  Exception( " The method or operation is not implemented. " );
    }

     #endregion
}

说明:

对于权限判断/操作日志等操作,这里集中操作了,当然也是在这里调用其它独立模块就行了,至于界面,就不用写权限判断和日志记录了。

2:界面调用

AOP 你想干什么 IOC 你服务什么 AOP 你想干什么 IOC 你服务什么

MAction action = new  MAction(TableNames.Users);
      action.SetAop( new  MyAop());//这句话怎么隐掉请看下面的MyAction的实现。
      action.Select(); // 权限操作
action.GetCount( " UserName='路过秋天' and Password='http://cyq1162.cnblogs.com' " ,  " Login " ); // 登陆操作
action.Close();

3:输出结果

Begin方法:权限判断执行:[Users表查询]
End 方法:操作日志:登陆结果:失败

说明:

1:对于GetCount,我们在最后增加了附加信息"Login"来标识是个登陆操作,对于Select,也同样可以附加标识,当然定义成枚举来标识就更便捷与清晰了。

2:好像界面调用里出现了SetAop方法,那每次操作都要来一次?能不能自动点,省的一行算一行?答案是可以的。

4:定义新的操作类MyAction,继承自MAction,如

AOP 你想干什么 IOC 你服务什么 AOP 你想干什么 IOC 你服务什么

public class  MyAction : CYQ.Data.MAction
{
    MyAop aop;
     public  MyAction( object  tableName):  base (tableName)
    {
        SetAop();
    }
     public  MyAction( object  tableName,  string  conn):  base (tableName, conn)
    {
        SetAop();
    }
     private void  SetAop()
    {
        aop  = new  MyAop();
         base .SetAop(aop);
    }
     public void  SetAopReuse()
    {
         base .SetAop(aop);
    }
}

说明:

这个时候,你界面调用就可以省略那句SetAop函数,甚至:

在你不需要日志时可以使用:action.SetNoAop();

接着又要重新使用日志功能:action.SetAopReuse();

OK,本篇写到这里也算结束了。

结言:

AOP 你想干什么 IOC 你服务什么 AOP 你想干什么 IOC 你服务什么

昨天扫了一天的Aop文章,相对来说本篇算是一个简单的总结,同时将其应用到 CYQ.Data 框架 里面,使用权限 / 操作日志 / 异常处理等的分离。

希望本篇对Aop或Ioc一无所知的人,看了也能略懂那么一点,深层点的请看博园的其它文章,免说我误导初学者。

本框架对Aop的最新应用请到 CYQ.Data 轻量数据层之路 bug反馈、优化建议、最新框架下载 下载抢先体验版本。

最后欢迎大家指导与交流,拒绝人参公鸡 ~~ 。

原文链接: http://www.cnblogs.com/cyq1162/archive/2010/09/24/1833670.html

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
kenx kenx
2年前
SpringBoot Aop 详解和多种使用场景
前言aop面向切面编程,是编程中一个很重要的思想本篇文章主要介绍的是SpringBoot切面Aop的使用和案例什么是aopAOP(AspectOrientedProgramming):面向切面编程,面向切面编程(也叫面向方面编程),是目前软件开发中的一个热点,也是Spring框架中的一个重要内容。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻
推荐学java 推荐学java
2年前
推荐学java——Spring之AOP
tips:本文首发在公众号逆锋起笔,本文源代码在公众号回复aop即可查看。什么是AOP?AOP(AspectOrientProgramming),直译过来就是面向切面编程。AOP是一种编程思想,是面向对象编程(OOP)的一种补充。面向对象编程将程序抽象成各个层次的对象,而面向切面编程是将程序抽象成各个切面。为什么需要AOP?实际开发中我们应
Stella981 Stella981
2年前
SpringBoot2.0 基础案例(11):配置AOP切面编程,解决日志记录业务
本文源码GitHub地址:知了一笑https://github.com/cicadasmile/springbootbase一、AOP切面编程1、什么是AOP编程在软件业,AOP为AspectOrientedProgramming的缩写,意为:面向切面编程,通
Wesley13 Wesley13
2年前
AOP相关概念
1.AOP(面向切面编程)在软件业,AOP为AspectOrientedProgramming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.AOP是OOP的延续,在软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生泛型.利用AOP
Easter79 Easter79
2年前
SpringBoot2.0 基础案例(11):配置AOP切面编程,解决日志记录业务
本文源码GitHub地址:知了一笑https://github.com/cicadasmile/springbootbase一、AOP切面编程1、什么是AOP编程在软件业,AOP为AspectOrientedProgramming的缩写,意为:面向切面编程,通
Easter79 Easter79
2年前
Spring的AOP逐层深入——AOP的基本原理(六)
什么是AOP    AOP(AspectOrientedProgramming),意思是面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP基于IoC基础,是对OOP(ObjectOrientedProgramming,面向对象)的延续。同时,AOP实际是GOF设计模式的延续,设计模式孜孜不倦
Stella981 Stella981
2年前
PostSharp 中 AOP 功能的简单使用
本文将介绍如何使用PostSharp中的AOP功能,实现在不修改原业务方法的情况下,记录方法运行的额外信息。PostSharp中AOP功能的简单使用独立观察员2021年2月21日年前在研究 .NET 中如何实现 AOP(AspectOrientedProgramming,面向切面的编程)时看到了一篇叫做《
Easter79 Easter79
2年前
SpringBoot系列之使用自定义注解校验用户是否登录
记得今年年初刚开始面试的时候,被问的最多的就是你知道Spring的两大核心嘛?那你说说什么是AOP,什么是IOC?我相信你可能也被问了很多次了。1、到底是什么是AOP?所谓AOP也就是面向切面编程,能够让我们在不影响原有业务功能的前提下,横切扩展新的功能。这里面有一个比较显眼的词我们需要注意一下,横切,它是基于横切面对程序进行扩展的。
Stella981 Stella981
2年前
SpringBoot系列之使用自定义注解校验用户是否登录
记得今年年初刚开始面试的时候,被问的最多的就是你知道Spring的两大核心嘛?那你说说什么是AOP,什么是IOC?我相信你可能也被问了很多次了。1、到底是什么是AOP?所谓AOP也就是面向切面编程,能够让我们在不影响原有业务功能的前提下,横切扩展新的功能。这里面有一个比较显眼的词我们需要注意一下,横切,它是基于横切面对程序进行扩展的。