天天看點

AOP面向切面程式設計(一)

本章将簡單介紹下AOP面向切面程式設計。

本章将簡單介紹下AOP面向切面程式設計。首先我們先來看些概念。

POP面向過程程式設計:符合邏輯思維,線性的處理問題-----無法應付複雜的系統。

OOP面向對象程式設計:

  萬物皆對象,對象互動完成功能,功能疊加成子產品,子產品組成系統,去搭建複雜的大型軟體系統。

  類卻是會變化的,增加日志/異常/權限/緩存/事務,隻能修改類?

  隻能替換整個對象,沒辦法把一個類動态改變。

  GOF的23種設計模式,應對變化,核心套路是依賴抽象,細節就可以變化。

AOP面向切面程式設計:

  是一種程式設計思想,是OOP思想的補充。

  允許開發者動态的修改靜态的OO模型,就像現實生活中對象在生命周期中會不斷的改變自身。    

  正是因為能夠動态的擴充功能,是以在程式設計時就可以有以下好處:

    1、隻需要聚焦核心業務邏輯,權限/異常/日志/緩存/事務等通用功能可以通過AOP方式添加,使程式設計變得更加簡單。

    2、功能動态擴充;集中管理;代碼複用;規範化;

  實作AOP的多種方式:

    1、靜态實作---裝飾器模式/代理模式。

    2、動态實作---Remoting/Castle(Emit)

    3、靜态織入---PostSharp(收費)---擴充編譯工具,生成的加入額外代碼。

    4、依賴注入容器的AOP擴充(開發)

    5、MVC的Filter---特性标記,然後該方法執行前/後就多了邏輯。

下面看一張圖來輔助我們了解:

AOP面向切面程式設計(一)

從圖中一刀切過去将核心業務邏輯和我們的通用功能分離,這樣的話我們隻需要聚焦核心業務邏輯,而權限/異常/日志/緩存/事務等通用功能可以通過AOP方式添加,使程式設計變得更加簡單。

下面我們重點來看下代碼如何實作,為了示範此處我們使用VS2017建個控制台項目MyAOP,目标架構為:.NET Framework 4.6.1,如下所示:

AOP面向切面程式設計(一)

一、代理模式實作靜态代理(靜态實作AOP)

using System;

namespace MyAOP
{
    /// <summary>
    /// 使用者類
    /// </summary>
    public class User
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Password { get; set; }
    }
}      
using System;

namespace MyAOP
{
    /// <summary>
    /// 代理模式實作靜态代理
    /// AOP 在方法前後增加自定義的方法
    /// </summary>
    public class ProxyAOP
    {
        public static void Show()
        {
            User user = new User()
            {
                Name = "浪子天涯",
                Password = "123456"
            };
            IUserProcessor processor = new UserProcessor();
            processor.RegUser(user);

            Console.WriteLine("***************");

            processor = new ProxyUserProcessor();
            processor.RegUser(user);
        }

        public interface IUserProcessor
        {
            void RegUser(User user);
        }

        public class UserProcessor : IUserProcessor
        {
            public void RegUser(User user)
            {
                Console.WriteLine("使用者已注冊。Name:{0},PassWord:{1}", user.Name, user.Password);
            }
        }

        /// <summary>
        /// 代理模式去提供一個AOP功能
        /// </summary>
        public class ProxyUserProcessor : IUserProcessor
        {
            private IUserProcessor _userProcessor = new UserProcessor();
            public void RegUser(User user)
            {
                BeforeProceed(user);
                this._userProcessor.RegUser(user);
                AfterProceed(user);
            }

            /// <summary>
            /// 業務邏輯之前
            /// </summary>
            private void BeforeProceed(User user)
            {
                Console.WriteLine("方法執行前");
            }

            /// <summary>
            /// 業務邏輯之後
            /// </summary>
            private void AfterProceed(User user)
            {
                Console.WriteLine("方法執行後");
            }
        }
    }
}      

看下調用ProxyAOP.Show()的結果:

AOP面向切面程式設計(一)

二、裝飾器模式實作靜态代理(靜态實作AOP)

using System;

namespace MyAOP
{
    /// <summary>
    /// 裝飾器模式實作靜态代理
    /// AOP 在方法前後增加自定義的方法
    /// </summary>
    public class DecoratorAOP
    {
        public static void Show()
        {
            User user = new User()
            {
                Name = "浪子天涯",
                Password = "88888888"
            };

            IUserProcessor processor = new UserProcessor();
            processor.RegUser(user);

            Console.WriteLine("***************");

            processor = new UserProcessorDecorator(processor);
            processor.RegUser(user);
        }

        public interface IUserProcessor
        {
            void RegUser(User user);
        }

        public class UserProcessor : IUserProcessor
        {
            public void RegUser(User user)
            {
                Console.WriteLine("使用者已注冊。Name:{0},PassWord:{1}", user.Name, user.Password);
            }
        }

        /// <summary>
        /// 裝飾器模式去提供一個AOP功能
        /// </summary>
        public class UserProcessorDecorator : IUserProcessor
        {
            private IUserProcessor _userProcessor { get; set; }
            public UserProcessorDecorator(IUserProcessor userprocessor)
            {
                this._userProcessor = userprocessor;
            }

            public void RegUser(User user)
            {
                BeforeProceed(user);

                this._userProcessor.RegUser(user);

                AfterProceed(user);
            }

            /// <summary>
            /// 業務邏輯之前
            /// </summary>
            private void BeforeProceed(User user)
            {
                Console.WriteLine("方法執行前");
            }

            /// <summary>
            /// 業務邏輯之後
            /// </summary>
            private void AfterProceed(User user)
            {
                Console.WriteLine("方法執行後");
            }
        }
    }
}      

看下調用DecoratorAOP.Show()的結果:

AOP面向切面程式設計(一)

3、使用Unity容器實作AOP

首先來看下項目的目錄結構:

AOP面向切面程式設計(一)

需要從NuGet上安裝如下程式包:

AOP面向切面程式設計(一)

核心業務邏輯:

using System;

namespace MyAOP.UnityWay
{
    public interface IUserProcessor
    {
        //[Obsolete] //此處可擴充
        void RegUser(User user);
        User GetUser(User user);
    }
}      
using System;

namespace MyAOP.UnityWay
{
    public class UserProcessor : IUserProcessor
    {
        public void RegUser(User user)
        {
            Console.WriteLine("使用者已注冊。");
        }

        public User GetUser(User user)
        {
            return user;
        }
    }
}      

AOP擴充:

using System;
using System.Collections.Generic;
using Unity.Interception.InterceptionBehaviors;
using Unity.Interception.PolicyInjection.Pipeline;

namespace MyAOP.UnityWay
{
    /// <summary>
    /// 緩存AOP擴充
    /// </summary>
    public class CachingBehavior : IInterceptionBehavior
    {
        /// <summary>
        /// 固定寫法
        /// </summary>
        public IEnumerable<Type> GetRequiredInterfaces()
        {
            return Type.EmptyTypes;
        }

        public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
        {
            Console.WriteLine("CachingBehavior");
            //input.Target.GetType().GetCustomAttributes()
            if (input.MethodBase.Name.Equals("GetUser"))
                return input.CreateMethodReturn(new User() { Id = 234, Name = "Eleven" });
            return getNext().Invoke(input, getNext);
        }

        /// <summary>
        /// 固定寫法
        /// </summary>
        public bool WillExecute
        {
            get { return true; }
        }
    }
}      
using System;
using System.Collections.Generic;
using Unity.Interception.InterceptionBehaviors;
using Unity.Interception.PolicyInjection.Pipeline;

namespace MyAOP.UnityWay
{
    public class ExceptionLoggingBehavior : IInterceptionBehavior
    {
        public IEnumerable<Type> GetRequiredInterfaces()
        {
            return Type.EmptyTypes;
        }

        public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
        {
            Console.WriteLine("ExceptionLoggingBehavior");
            IMethodReturn methodReturn = getNext()(input, getNext);
            if (methodReturn.Exception == null)
            {
                Console.WriteLine("無異常");
            }
            else
            {
                Console.WriteLine($"異常:{methodReturn.Exception.Message}");
            }

            return methodReturn;
        }

        public bool WillExecute
        {
            get { return true; }
        }
    }
}      
using System;
using System.Collections.Generic;
using Unity.Interception.InterceptionBehaviors;
using Unity.Interception.PolicyInjection.Pipeline;

namespace MyAOP.UnityWay
{
    public class LogAfterBehavior : IInterceptionBehavior
    {
        public IEnumerable<Type> GetRequiredInterfaces()
        {
            return Type.EmptyTypes;
        }

        public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
        {
            Console.WriteLine("LogAfterBehavior");
            foreach (var item in input.Inputs)
            {
                Console.WriteLine(item.ToString());//反射擷取更多資訊
            }
            IMethodReturn methodReturn = getNext()(input, getNext);
            Console.WriteLine("LogAfterBehavior" + methodReturn.ReturnValue);
            return methodReturn;
        }

        public bool WillExecute
        {
            get { return true; }
        }
    }
}      
using System;
using System.Collections.Generic;
using Unity.Interception.InterceptionBehaviors;
using Unity.Interception.PolicyInjection.Pipeline;

namespace MyAOP.UnityWay
{
    /// <summary>
    /// 不需要特性
    /// </summary>
    public class LogBeforeBehavior : IInterceptionBehavior
    {
        public IEnumerable<Type> GetRequiredInterfaces()
        {
            return Type.EmptyTypes;
        }

        public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
        {
            Console.WriteLine("LogBeforeBehavior");
            foreach (var item in input.Inputs)
            {
                Console.WriteLine(item.ToString());//反射擷取更多資訊
            }
            return getNext().Invoke(input, getNext);
        }

        public bool WillExecute
        {
            get { return true; }
        }
    }
}      
using System;
using System.Collections.Generic;
using System.Diagnostics;
using Unity.Interception.InterceptionBehaviors;
using Unity.Interception.PolicyInjection.Pipeline;

namespace MyAOP.UnityWay
{
    /// <summary>
    /// 性能監控的AOP擴充
    /// </summary>
    public class MonitorBehavior : IInterceptionBehavior
    {
        public IEnumerable<Type> GetRequiredInterfaces()
        {
            return Type.EmptyTypes;
        }

        public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
        {
            Console.WriteLine(this.GetType().Name);
            string methodName = input.MethodBase.Name;
            Stopwatch stopwatch = new Stopwatch();
            stopwatch.Start();

            var methodReturn = getNext().Invoke(input, getNext);//後續邏輯執行

            stopwatch.Stop();
            Console.WriteLine($"{this.GetType().Name}統計方法{methodName}執行耗時{stopwatch.ElapsedMilliseconds}ms");

            return methodReturn;
        }

        public bool WillExecute
        {
            get { return true; }
        }
    }
}      
using System;
using System.Collections.Generic;
using Unity.Interception.InterceptionBehaviors;
using Unity.Interception.PolicyInjection.Pipeline;

namespace MyAOP.UnityWay
{
    public class ParameterCheckBehavior : IInterceptionBehavior
    {
        public IEnumerable<Type> GetRequiredInterfaces()
        {
            return Type.EmptyTypes;
        }

        public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
        {
            Console.WriteLine("ParameterCheckBehavior");
            User user = input.Inputs[0] as User;
            if (user.Password.Length < 10)
            {
                return input.CreateExceptionMethodReturn(new Exception("密碼長度不能小于10位"));
            }
            else
            {
                Console.WriteLine("參數檢測無誤");
                return getNext().Invoke(input, getNext);
            }
        }

        public bool WillExecute
        {
            get { return true; }
        }
    }
}      

Unity.config配置檔案:

<configuration>
  <configSections>
    <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Unity.Configuration"/>
    <!--Microsoft.Practices.Unity.Configuration.UnityConfigurationSection-->
  </configSections>
  <unity>
    <sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension, Unity.Interception.Configuration"/>
    <containers>
      <container name="aopContainer">
        <extension type="Interception"/>
        <register type="MyAOP.UnityWay.IUserProcessor,MyAOP" mapTo="MyAOP.UnityWay.UserProcessor,MyAOP">
          <interceptor type="InterfaceInterceptor"/>
          <interceptionBehavior type="MyAOP.UnityWay.MonitorBehavior, MyAOP"/>

          <interceptionBehavior type="MyAOP.UnityWay.LogBeforeBehavior, MyAOP"/>
          <interceptionBehavior type="MyAOP.UnityWay.ParameterCheckBehavior, MyAOP"/>
          <interceptionBehavior type="MyAOP.UnityWay.CachingBehavior, MyAOP"/>
          <interceptionBehavior type="MyAOP.UnityWay.ExceptionLoggingBehavior, MyAOP"/>
          <interceptionBehavior type="MyAOP.UnityWay.LogAfterBehavior, MyAOP"/>

        </register>
      </container>
    </containers>
  </unity>
</configuration>      

注意:編譯時需要将配置檔案輸出到bin/debug目錄下,設定如下所示:

AOP面向切面程式設計(一)

使用如下:

using System;
using System.IO;
using System.Configuration;
using Microsoft.Practices.Unity.Configuration;
using Unity;

namespace MyAOP.UnityWay
{
    public class UnityConfigAOP
    {
        public static void Show()
        {
            User user = new User()
            {
                Name = "浪子天涯",
                Password = "12345678910"
            };
            //配置UnityContainer
            IUnityContainer container = new UnityContainer();
            ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap();
            fileMap.ExeConfigFilename = Path.Combine(AppDomain.CurrentDomain.BaseDirectory + "CfgFiles\\Unity.config");
            Configuration configuration = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);

            UnityConfigurationSection configSection = (UnityConfigurationSection)configuration.GetSection(UnityConfigurationSection.SectionName);
            configSection.Configure(container, "aopContainer");

            IUserProcessor processor = container.Resolve<IUserProcessor>();
            processor.RegUser(user);
            processor.GetUser(user);
        }
    }
}      

調用UnityConfigAOP.Show()的結果如下:

AOP面向切面程式設計(一)

可以發現執行順序就像俄羅斯套娃,如下所示:

AOP面向切面程式設計(一)

Demo源碼:

連結:https://pan.baidu.com/s/147Veb1fU49sT5bcEbgrERw 
提取碼:j5ml      

此文由部落客精心撰寫轉載請保留此原文連結:https://www.cnblogs.com/xyh9039/p/13532063.html    

版權聲明:如有雷同純屬巧合,如有侵權請及時聯系本人修改,謝謝!!!