简单学习一下IOC和AOP

聊一聊 IOC& AOP之前,先解释几个问题:

  • AOP的老大哥OOP和老老大哥POP
  • 什么是IoC?
  • IoC 解决了什么问题?
  • 什么是 AOP?
  • AOP 解决了什么问题?
  • AOP 为什么叫做切面编程?
  1. 什么是POP,OOP?

    1. POP (Procedure-Oriented Programming)即面向过程编程:

      ​ “面向过程”(Procedure Oriented)是一种以过程为中心的编程思想。这些都是以什么正在发生为主要目标进行编程,不同于面向对象的是谁在受影响。与面向对象明显的不同就是封装继承。简写为POP --百度百科

      说白了就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以。

    2. OOP(Object Oriented Programming)即面向对象编程:

      面向对象编程OOP)是一种基于“对象”概念的编程范式,它可以包含数据和代码:字段形式的数据(通常称为属性属性)和代码形式的过程(通常称为方法)。--维基百科

      ​ 面向对象程序设计方法是尽可能模拟人类的思维方式,使得软件的开发方法与过程尽可能接近人类认识世界、解决现实问题的方法和过程,也即使得描述问题 的问题空间与问题的解决方案空间在结构上尽可能一致,把客观世界中的实体抽象为问题域中的对象。

      ​ 它具有三大特性:封装继承多态

  2. 什么是IoC?

    1. IoC (Inversion of control )控制反转/反转控制。它是一种思想不是一个技术实现。描述的是 :软件系统开发中领域对象的创建以及管理的问题

      例如:现在有类A依赖于类B

      • 传统开发方式(OOP):在类 A 中手动通过 new 关键字来 new 一个 B 对象出来。
      • 使用IOC思想的开发方式:不通过 new 关键字来创建对象,而是通过 IoC 容器来帮助我们实例化对象。我们需要哪个对象,直接从 IoC 容器里面取出即可。
    2. 所以使用IoC思想我们丧失了创建、管理对象的权力,但是省去了我们去创建,管理对象的麻烦

    3. 理解一下什么叫控制反转

      • 控制:指的是对象创建(实例化、管理)的权力
      • 反转:控制权交给外部环境(IoC 容器)

  3. IoC 解决了什么问题?

    1. IOC出现的目的就是去除两者之间的相互依赖,由三方管理相关资源

      • 降低耦合度
      • 易于资源管理(例如绝大部分IOC容器默认管理的就是单例,帮你实现单例
    2. 假如有如下场景

    如果随时代变迁,人回家的交通工具由马变成了汽车,那么我们需要在所有的人类中将交通工具的属性初始化修改为汽车的实现类像这样

    那么我们如果使用IOC的思想,我们将对象的控制权(创建、管理)交给 IoC 容器去管理,我们在使用的时候由容器来提供

    这样如果随着时代变迁交通再升级为飞机,那我们只需要调整容器就可以,不需要再每个依赖它的地方去修改实现;

    1. 说到IoC 那就一定要提DI

      ​ IoC 最常见以及最合理的实现方式叫做依赖注入(Dependency Injection,简称 DI)。

      DI-Dependency Injection,即“依赖注入”:组件之间依赖关系由容器在运行期决定,形象的说,即由容器动态的将某个依赖关系注入到组件之中。依赖注入的目的并非为软件系统带来更多功能,而是为了提升组件重用的频率,并为系统搭建一个灵活、可扩展的平台。

      主要的依赖注入方式

      • 构造器注入
      • 属性注入
      • 方法注入
  4. 什么是AOP?

    1. AOP就是面向切面编程

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

      它既然是OOP的一个延续,那就从OOP开始演化。

      假设有以下模型

      • Horse、 Pig、 Dog,这三个类中都有 eat 和 run 两个方法。
      • 通过 OOP 思想中的继承,我们可以提取出一个 Animal 的父类,然后将 eat 和 run 方法放入父类中,HorsePigDog通过继承Animal类即可自动获得 eat() 和 run() 方法。

    ​ OOP 编程思想可以解决大部分的代码重复问题。但是有一些问题是处理不了的。比如:日志记录、性能统计、安全校验、事务管理,等等。这些辅助逻辑往往贯穿你整个核心业务,传统 OOP 很难将其封装:

        public class Animal
    {
    public void Eat(object param)
    {
    Console.WriteLine("---安全校验---");
    Console.WriteLine("---性能统计 Start---");
    Console.WriteLine("---日志打印 Start---");
    Console.WriteLine("---事务管理 Start---"); Console.WriteLine("它吃了!!!!!!!!!!!!!"); Console.WriteLine("---事务管理 End---");
    Console.WriteLine("---日志打印 End---");
    Console.WriteLine("---性能统计 End---");
    } public void Run(object param)
    {
    Console.WriteLine("---安全校验---");
    Console.WriteLine("---性能统计 Start---");
    Console.WriteLine("---日志打印 Start---");
    Console.WriteLine("---事务管理 Start---"); Console.WriteLine("它跑啦!!!!!!!!!!!!!"); Console.WriteLine("---事务管理 End---");
    Console.WriteLine("---日志打印 End---");
    Console.WriteLine("---性能统计 End---");
    }
    } public class Pig : Animal
    {
    public new void Eat(object param)
    {
    Console.WriteLine("---安全校验---");
    Console.WriteLine("---性能统计 Start---");
    Console.WriteLine("---日志打印 Start---");
    Console.WriteLine("---事务管理 Start---"); Console.WriteLine("它吃了麸皮!!!!!!!!!!!!!"); Console.WriteLine("---事务管理 End---");
    Console.WriteLine("---日志打印 End---");
    Console.WriteLine("---性能统计 End---");
    }
    public new void Run(object param)
    {
    Console.WriteLine("---安全校验---");
    Console.WriteLine("---性能统计 Start---");
    Console.WriteLine("---日志打印 Start---");
    Console.WriteLine("---事务管理 Start---"); Console.WriteLine("它跑出猪圈啦!!!!!!!!!!!!!"); Console.WriteLine("---事务管理 End---");
    Console.WriteLine("---日志打印 End---");
    Console.WriteLine("---性能统计 End---");
    }
    }

    OOP 是至上而下的编程方式,犹如一个树状图,A调用B、B调用C,或者A继承B、B继承C。这种方式对于业务逻辑来说是合适的,通过调用或继承以复用。而辅助逻辑就像一把闸刀横向贯穿所有方法

    所以AOP正是为了解决这一问题而诞生的技术

    结论:

    ​ AOP 不是 OOP 的对立面,它是对 OOP 的一种补充。OOP 是纵向的,AOP 是横向的,两者相结合方能构建出良好的程序结构。AOP 技术,让我们能够不修改原有代码,便能让切面逻辑在所有业务逻辑中生效

    1. 应用场景

      • 参数校验和判空
      • 权限控制
      • 日志记录
      • 性能统计
      • 事务处理
      • 异常处理
      • ...
  5. 利用AutoFac实现一个简单AOP

    1. 创建动态代理 ,核心就是实现了DispatchProxy这个调度代理抽象类,这个代理的作用是实现切面的功能,例如以下代理实现了方法执行前,方法执行后,及异常捕获

      internal class DynamicProxy<T> : DispatchProxy
      {
      public T? decorated { get; set; }//目标类
      public Action<object?[]?>? _BeforeAction { get; set; } // 动作之前执行
      public Action<object?[]?, object>? _AfterAction { get; set; } // 动作之后执行
      public Action<Exception>? _CatchExceptionAction { get; set; } // 捕获异常之后执行 protected override object? Invoke(MethodInfo? targetMethod, object?[]? args)
      {
      Exception exception = null; Before(args); object result = null;
      try
      {
      //调用实际目标对象的方法
      result = targetMethod?.Invoke(decorated, args);
      }
      catch (Exception ex)
      {
      exception = ex;
      } After(args, result); //调用完执行方法后的委托,如果有异常,抛出异常
      if (exception != null)
      {
      CatchException(exception);
      }
      return result;
      } /// <summary>
      /// 创建代理实例
      /// </summary>
      /// <param name="decorated">代理的接口类型</param>
      /// <param name="beforeAction">方法执行前执行的事件</param>
      /// <param name="afterAction">方法执行后执行的事件</param>
      /// <param name="catchException">异常捕获后执行的事件</param>
      /// <returns></returns>
      public T Create(T decorated, Action<object?[]?> beforeAction, Action<object?[]?, object> afterAction, Action<Exception> catchException)
      {
      // 调用DispatchProxy 的Create 创建一个新的T
      object proxy = Create<T, DynamicProxy<T>>();
      DynamicProxy<T> proxyDecorator = (DynamicProxy<T>)proxy;
      proxyDecorator.decorated = decorated;
      //把自定义的方法委托给代理类
      proxyDecorator._AfterAction = afterAction;
      proxyDecorator._BeforeAction = beforeAction;
      proxyDecorator._CatchExceptionAction = catchException;
      return (T)proxy;
      } private void Before(object?[]? args)
      {
      try
      {
      _BeforeAction.Invoke(args);
      }
      catch (Exception ex)
      {
      Console.WriteLine($"执行之前异常:{ex.Message}");
      }
      } private void After(object?[]? args, object? result)
      {
      try
      {
      _AfterAction.Invoke(args, result);
      }
      catch (Exception ex)
      {
      Console.WriteLine($"执行之后异常:{ex.Message}");
      }
      } private void CatchException(Exception ex)
      {
      _CatchExceptionAction(ex);
      } }
    2. 创建动态代理工厂类 ,它是泛型工厂,用于创建不同类型的代理类

        class DynamicProxyFactory
      {
      /// <summary>
      /// 创建代理实例
      /// </summary>
      /// <param name="decorated">代理的接口类型</param>
      /// <returns></returns>
      public static T Create<T>()
      {
      var decorated = ServiceHelp.GetService<T>(typeof(T));
      var type = decorated.GetType();
      var interceptAttribut = type.GetCustomAttribute<InterceptAttribut>();
      var interceptor = ServiceHelp.GetService<IInterceptor>(interceptAttribut.Type);
      //创建代理类
      var proxy = new DynamicProxy<T>().Create(decorated, interceptor.BeforeExecuted, interceptor.AfterExecuted, interceptor.CatchException);
      return proxy;
      }
      }
    3. 在工厂创建动态代理类时,需要用到两个工具

      1. 一个是标记AOP切点的Attribute--InterceptAttribut(拦截器属性)

          /// <summary>
        /// 自定义拦截器特性
        /// </summary>
        [AttributeUsage(AttributeTargets.Class)]
        internal class InterceptAttribut : Attribute
        {
        public Type Type { get; set; }
        public InterceptAttribut(Type type)
        {
        this.Type = type;
        }
        }
      2. 第二个就是获取实例的ServiceHelp,其核心就是以Autofac这个IOC容器去注册及获取服务.

          internal class ServiceHelp
        {
        //实例化Autofac容器
        private static ContainerBuilder builder = new ContainerBuilder();
        public static IContainer? serviceProvider { get; set; } public static void BuildServiceProvider(IServiceCollection services)
        {
        //将collection中的服务填充到Autofac
        builder.Populate(services); //注册InstanceModule组件
        builder.RegisterModule<InstanceModule>(); //创建容器
        serviceProvider = builder.Build();
        } internal static T GetService<T>(Type serviceType)
        {
        return (T)serviceProvider.Resolve(serviceType);
        }
        } public class InstanceModule : Autofac.Module
        {
        protected override void Load(ContainerBuilder builder)
        {
        builder.RegisterType<InterceptAttribut>();
        //builder.RegisterType<Horse>().As<ITransportation>();
        builder.RegisterType<Car>().As<ITransportation>();
        builder.RegisterType<ExecutAOP>();
        }
        }
    4. 接下来就需要我们创建这个AOP切面

      /// <summary>
      /// 自定义拦截器接口
      /// </summary>
      interface IInterceptor
      {
      /// <summary>
      /// 执行前
      /// </summary>
      /// <param name="args"></param>
      void BeforeExecuted(object?[]? args);
      /// <summary>
      /// 执行后
      /// </summary>
      /// <param name="args">参数</param>
      /// <param name="result">返回值</param>
      void AfterExecuted(object?[]? args, object? result); void CatchException(Exception ex); }
      /// <summary>
      /// 方法执行的切面
      /// </summary>
      class ExecutAOP : IInterceptor
      {
      public void AfterExecuted(object?[]? args, object? result)
      {
      Console.WriteLine($"拦截器中方法后执行~~~~");
      } public void BeforeExecuted(object?[]? args)
      {
      if (args != null && args.Length > 0 && args[0] == null)
      throw new Exception("参数错误");
      Console.WriteLine($"拦截器中方法前执行~~~~"); }
      public void CatchException(Exception ex)
      {
      Console.WriteLine($"拦截器中捕获到了异常~~~~\r\n{ex.InnerException.Message}");
      }
      }
    5. 设定一个业务场景,有一个交通工具接口有两个公共方法 Run() 、Eat(),以及其两个实现, Hours 和Car

       interface ITransportation
      {
      public void Run();
      public void Eat(string food); } [InterceptAttribut(typeof(ExecutAOP))]
      class Horse : ITransportation
      {
      public void Eat(string food)
      {
      Console.WriteLine($"小马儿吃了{food}~~~~~~~~~~~~");
      } public void Run()
      {
      Console.WriteLine("马儿马儿快马加鞭~~~~~~~~~~~~");
      } }
      [InterceptAttribut(typeof(ExecutAOP))]
      class Car : ITransportation
      {
      public void Eat(string food)
      {
      Console.WriteLine($"大奔驰吃了{food}~~~~~~~~~~~~~~~");
      } public void Run()
      {
      Console.WriteLine("奔驰奔驰跑的快~~~~~~~~~~~~~~~");
      throw new Exception("奔驰撞了");
      }
      }
    6. 效果

      从上图可以看到结果,我们在业务逻辑中只是对业务类添加了 [InterceptAttribut(typeof(ExecutAOP))] 标记,就实现了切面中添加处理,实现了AOP思想

了解一下IOC和AOP的更多相关文章

  1. Spring的IOC和AOP之深剖

    今天,既然讲到了Spring 的IOC和AOP,我们就必须要知道 Spring主要是两件事: 1.开发Bean:2.配置Bean.对于Spring框架来说,它要做的,就是根据配置文件来创建bean实例 ...

  2. spring的IOC和AOP协同工作

    看网络上的spring资料,基本都是在讲解IOC和AOP,但是二者是如何协同工作的,说的很少. 粗略调试了下BeanFactory的创建过程,发现是如图所示的大概过程.其中BeanPostProces ...

  3. spring - ioc和aop

    1.程序中为什么会用到spring的ioc和aop 2.什么是IOC,AOP,以及使用它们的好处,即详细回答了第一个问题 3.原理 关于1: a:我们平常使用对象的时候,一般都是直接使用关键字类new ...

  4. spring的IOC和AOP

     spring的IOC和AOP 1.解释spring的ioc? 几种注入依赖的方式?spring的优点? IOC你就认为他是一个生产和管理bean的容器就行了,原来需要在调用类中new的东西,现在都是 ...

  5. Castle框架中的IOC和AOP机制

    反转控制(IOC)和面向切面编程(AOP)技术作为当前比较流行的技术,其优势已受到广泛关注,但是这两项新技术在实际项目上的应用研究却很落后,而且在.NET平台下实现这两项技术没有形成可以广泛套用的框架 ...

  6. 【转】spring - ioc和aop

    [转]spring - ioc和aop 1.程序中为什么会用到spring的ioc和aop 2.什么是IOC,AOP,以及使用它们的好处,即详细回答了第一个问题 3.原理 关于1: a:我们平常使用对 ...

  7. 深入浅出学习Spring框架(四):IoC和AOP的应用——事务配置

    在前文 深入浅出学习Spring框架(一):通过Demo阐述IoC和DI的优势所在. 深入浅出学习Spring框架(三):AOP 详解 分别介绍了Spring的核心功能——IoC和AOP,光讲知识远远 ...

  8. Spring入门导读——IoC和AOP

    和MyBatis系列不同的是,在正式开始Spring入门时,我们先来了解两个关于Spring核心的概念,IoC(Inverse of Control)控制反转和AOP()面向切面编程. 1.IoC(I ...

  9. 六:Ioc和AOP使用拓展

    Ioc和AOP使用拓展 一:1.构造注入 一个<constructor-arg>元素表示构造方法的一个参数,且使用时不区分顺序,index指定元素,位置从0开始,Type用来指定参数,避免 ...

  10. 反射应用--IOC和AOP

    反射最大的价值就是用来写框架,下面贴出自己的3篇代码,模拟实现SPING框架的bean工厂,IOC,AOP.当然这里重点是在利用反射实现功能,为了图方便,我用的是Properties文件,关于XML后 ...

随机推荐

  1. Django笔记四十二之model使用validator验证器

    本文首发于公众号:Hunter后端 原文链接:Django笔记四十二之model使用validator验证器 这一篇笔记介绍一下 model 里的 validator 验证器. 首先,这是个什么东西呢 ...

  2. springboot整合nacos的入门Demo

    Nacos介绍 Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service的首字母简称,一个更易于构建云原生应用的动态服务发现.配置管理和服务 ...

  3. FaceFusion:探索无限创意,创造独一无二的面孔融合艺术!

    FaceFusion:探索无限创意,创造独一无二的面孔融合艺术! 它使用先进的图像处理技术,允许用户将不同的面部特征融合在一起,创造有趣和令人印象深刻的效果.这个项目的潜在应用包括娱乐.虚拟化妆和艺术 ...

  4. 深度学习基础入门篇[六(1)]:模型调优:注意力机制[多头注意力、自注意力],正则化【L1、L2,Dropout,Drop Connect】等

    深度学习基础入门篇[六(1)]:模型调优:注意力机制[多头注意力.自注意力],正则化[L1.L2,Dropout,Drop Connect]等 1.注意力机制 在深度学习领域,模型往往需要接收和处理大 ...

  5. ICLR 2024 | Mol-Instructions: 面向大模型的大规模生物分子指令数据集

    Mol-Instructions: 面向大模型的大规模生物分子指令数据集 发表会议:ICLR 2024 论文标题:Mol-Instructions: A Large-Scale Biomolecula ...

  6. 小知识:杜绝明文密码,OGG的credentialstore特性

    之前OGG配置文件中都会明文记录密码,而在OGG12c及以上版本中,有一个特性credentialstore,可以用来杜绝明文密码,提升安全性. 这里测试添加credentialstore并配置数据库 ...

  7. SESSION会话机制解析

    Windows Session(会话)的概念 会话 session 是由代表单个用户登录会话的所有进程和系统对象组成的.其中的对象包括所有的窗口,桌面和windows stations.桌面是特定se ...

  8. 到什么程度才叫精通 Linux?

    大家好,我是陶朱公Boy,一个认真生活,总想超越自己的程序员. 前言 知乎上有一个提问:到什么程度才叫精通 Linux?                              ↓↓↓ 今天,我们就 ...

  9. npm无法安装node-sass 的问题

    安装 node-sass 的问题呈现:4.9.0版本无法下载 Downloading binary from https://github.com/sass/node-sass/releases/do ...

  10. 走出人生的舒适区,告别 CRUD

    ​舒适区(Comfort zone),指的是一个人所处的一种环境的状态,和习惯的行动,人会在这种安乐窝的状态中感到舒适并且缺乏危机感. 工作中的舒适区 很多人工作也每天很累很辛苦,程序员每天都在加班加 ...