ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

AOP是什么?为什么要使用AOP

2022-04-20 13:33:49  阅读:187  来源: 互联网

标签:为什么 创建 代码 AOP 代理 使用 日志 动态


一、AOP简介
AOP的全称是Aspect-Oriented Programming,即面向切面编程(也称面向方面编程)。它是面向对象编程(OOP)的一种补充,目前已成为一种比较成熟的编程方式。

在传统的业务处理代码中,通常都会进行事务处理、日志记录等操作。虽然使用OOP可以通过组合或者继承的方式来达到代码的重用,但如果要实现某个功能(如日志记录),同样的代码仍然会分散到各个方法中。这样,如果想要关闭某个功能,或者对其进行修改,就必须要修改所有的相关方法。这不但增加了开发人员的工作量,而且提高了代码的出错率。

为了解决这一问题,AOP思想随之产生。AOP采取横向抽取机制,将分散在各个方法中的重复代码提取出来,然后在程序编译或运行时,再将这些提取出来的代码应用到需要执行的地方。这种采用横向抽取机制的方式,采用传统的OOP思想显然是无法办到的,因为OOP只能实现父子关系的纵向的重用。虽然AOP是一种新的编程思想,但却不是OOP的替代品,它只是OOP的延伸和补充。

在AOP思想中,类与切面的关系如下图所示。从图中可以看出,通过Aspect(切面)分别在Class1和Class2的方法中加入了事务、日志、权限和异常等功能。


 

AOP的使用,使开发人员在编写业务逻辑时可以专心于核心业务,而不用过多的关注于其他业务逻辑的实现,这不但提高了开发效率,而且增强了代码的可维护性。

二、AOP的实现

我们在上面讲解了有关AOP的一些理论知识,那么如何在代码里面实现呢?

实现AOP有两种方式:

  • 静态代理实现。所谓静态代理,就是我们自己来写代理对象。
  • 动态代理实现。所谓动态代理,就是在程序运行时,去生成一个代理对象。

1、静态代理

实现静态代理需要使用到两种设计模式:装饰器模式和代理模式。

装饰器模式:允许向一个现有的对象添加新的功能,同时又不改变这个现有对象的结构。属于结构型设计模式,它是作为现有类的一种包装。首先会创建一个装饰类,用来包装原有的类,并在保持类的完整性的前提下,提供额外的功能。
看下面的例子。

我们首先创建一个User类:

 

 

 接着我们创建一个账号服务的接口,里面有一个方法,用来注册一个用户:

 

 

 然后创建一个类来实现上面的接口:

  

 我们在创建一个装饰器类:

 

  我们会发现装饰器类同样实现了IAccountService接口。最后我们在Main方法里面调用:

 

 

代理模式:即一个类代表另一个类的功能。我们会创建一个代理类,这个代理类和装饰器类基本一样。

 

调用方式更简单。不再这里演示了。
这里的静态代理方式有一些缺陷,虽然确保了业务类职责单一,但如果需要代理的类很多,那么我们需要写大量的辅助类,工作量非常大。
所以实际用的比较多的就是如下所示的动态代理。

2、动态代理

动态代理实现也有两种方式;

  • 通过代码织入的方式。例如PostSharp第三方插件。我们知道.NET程序最终会编译成IL中间语言,在编译程序的时候,PostSharp会动态的去修改IL,在IL里面添加代码,这就是代码织入的方式。
  • 通过反射的方式实现。通过反射实现的方法非常多,也有很多实现了AOP的框架,例如Unity、MVC过滤器、Autofac等。

我们先来看看如何使用PostSharp实现动态代理。PostSharp是一款收费的第三方插件。

首先新创建一个控制台应用程序,然后创建一个订单业务类:

 

 接着在Main方法里面调用:

 

 这时又提出了一个新的需求,要去添加一个日志功能,记录业务的执行情况,按照以前的办法,需要定义一个日志帮助类:

 

 如果不使用AOP,我们就需要在记录日志的地方实例化Loghelper对象,然后记录日志:

 

 

 

 这样修改可以实现记录日志的功能。但是上面的方法会修改原先已有的代码,这就违反了开闭原则。而且添加日志也不是业务需求的变动,不应该去修改业务代码。

下面使用AOP来实现。首先安装PostSharp,直接在NuGet里面搜索,然后安装即可:

 

 然后定义一个LogAttribute类,继承自OnMethodBoundaryAspect。这个Aspect提供了进入、退出函数等连接点方法。另外,Aspect上必须设置“[Serializable] ”,这与PostSharp内部对Aspect的生命周期管理有关:

 

 然后Log特性应用到DoWork函数上面:

 

 这样修改以后,只需要在方法上面添加一个特性,以前记录日志的代码就可以注释掉了,这样就不会再修改业务逻辑代码了,运行程序:

 

 

这样就实现了AOP功能。

我们在看看使用Remoting来实现动态代理。

首先还是创建一个User实体类:

 

 然后创建一个接口,里面有一个注册方法:

 

 然后创建接口的实现类:

 

 然后创建一个泛型的动态代理类:

 

我们看到,这个泛型动态代理类里面有两个泛型委托:BeforeAction、AfterAction。通过构造函数把代理泛型类传递进去。最后调用Invoke方法执行代理类的方法。
最后我们还要创建一个代理工厂类,用来创建代理对象,通过调用动态代理来创建动态代理对象:

using System;
 
namespace DynamicProxy
{
    /// <summary>
    /// 动态代理工厂类
    /// </summary>
    public static class ProxyFactory
    {
        public static T Create<T>(Action before, Action after)
        {
            // 实例化被代理泛型对象
            T instance = Activator.CreateInstance<T>();
            // 实例化动态代理,创建动态代理对象
            var proxy = new DynamicProxy<T>(instance) { BeforeAction = before, AfterAction = after };
            // 返回透明代理对象
            return (T)proxy.GetTransparentProxy();
        }
    }
}

我们最后在Main方法里面调用:

using DynamicProxy.Model;
using DynamicProxy.Services;
using System;
 
namespace DynamicProxy
{
    class Program
    {
        static void Main(string[] args)
        {
            // 调用动态代理工厂类创建动态代理对象,传递AccountService,并且传递两个委托
            var acount = ProxyFactory.Create<AccountService>(before:() =>
            {
                Console.WriteLine("注册之前");
            }, after:() =>
            {
                Console.WriteLine("注册之后");
            });
 
            User user = new User() 
            {
             Name="张三",
             Password="123456"
            };
            // 调用注册方法
            acount.Reg(user);
 
            Console.ReadKey();
        }
    }
}

 

标签:为什么,创建,代码,AOP,代理,使用,日志,动态
来源: https://www.cnblogs.com/SF8588/p/16169227.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有