6、UnityConfig實現AOP

需求:我們需要給已經開發好的服務如這裏的UserService,添加額外的執行邏輯,但是又不想破壞原有的服務,如:我們需要給UserService添加監控邏輯,監控的目的是看UserService服務裏的RegUser方法和GetUser方法的執行時間消耗

1、定義1個用戶接口

namespace UnityConfigAOP
{
    public interface IUserService
    {
        void RegUser(User user);

        User GetUser(User user);
    }
}

2、實現用戶這個接口

namespace UnityConfigAOP
{
    public class UserService:IUserService
    {
        public void RegUser(User user)
        {
            Console.WriteLine("用戶已註冊。");
        }

        public User GetUser(User user)
        {
            Console.WriteLine("得到用戶信息。");
            return user;
        }
    }
}

3、Unity配置文件
3.1、需要引用如下圖這5個程序集

3.1、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="UnityConfigAOP.IUserService,UnityConfigAOP" mapTo="UnityConfigAOP.UserService,UnityConfigAOP">
          <interceptor type="InterfaceInterceptor"/>
          <interceptionBehavior type="UnityConfigAOP.AOPBehavior.MonitorBehavior, UnityConfigAOP"/>
        </register>
      </container>
    </containers>
  </unity>
</configuration>

3.2、接口方法不需要某個AOP擴展怎麼辦呢?在方法上加個CustomNOAOPAttribute自定義屬性,在執行MonitorBehavior類的Invoke方法裏用特性input.Target.GetType().IsDefined(typeof(CustomNOAOPAttribute), true)去判斷一下

3.3、MonitorBehavior監控行爲額外邏輯代碼

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Unity.Interception.InterceptionBehaviors;
using Unity.Interception.PolicyInjection.Pipeline;

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

        public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
        {
            var type = input.Target.GetType();
            string methodName = input.MethodBase.Name;
            if (type.IsDefined(typeof(CustomNOAOPAttribute), true))
            {
                var method = getNext().Invoke(input, getNext);//後續邏輯執行
                return method;
            }

            MethodInfo currentMethod = type.GetMethod(methodName);
            if (currentMethod.IsDefined(typeof(CustomNOAOPAttribute), true))//檢查方法有沒有定義此屬性
            {
                var method = getNext().Invoke(input, getNext);//後續邏輯執行
                return method;
            }

            Console.WriteLine(this.GetType().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; }
        }
    }
}

4、客戶端調用UserService服務

namespace UnityConfigAOP
{
    class Program
    {
        static void Main(string[] args)
        {
            User user = new User()
            {
                Name = "David.Meng",
                Password = "123456"
            };
            //配置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");

            IUserService userService = container.Resolve<IUserService>();
            userService.RegUser(user);
            userService.GetUser(user);
        }
    }
}

5、調試代碼
執行userService.RegUser(user);代碼的時候,並沒有直接進入到RegUser(User user);方法裏面,而是先進到MonitorBehavior類的Invoke方法裏,直到執行到getNext().Invoke(input, getNext);這句代碼才真正的進入到RegUser(User user);方法裏面

 

7、項目截圖,我們可以配置多個AOP行爲不光是監控行爲,還可以配置日誌行爲,異常行爲,緩存行爲等等,如下圖所示

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章