Lind.DDD.Aspects通過Plugins實現方法的動態攔截~Lind里的AOP

来源:http://www.cnblogs.com/lori/archive/2016/12/06/6139345.html
-Advertisement-
Play Games

回到目錄 .Net MVC之所以發展的如些之好,一個很重要原因就是它公開了一組AOP的過濾器,即使用這些過濾器可以方便的攔截controller里的action,並註入我們自己的代碼邏輯,向全局的異常記錄,用戶授權,Url授權,操作行為記錄等,這一大批Lind的基本組件都是實現MVC和API的過濾實 ...


回到目錄

.Net MVC之所以發展的如些之好,一個很重要原因就是它公開了一組AOP的過濾器,即使用這些過濾器可以方便的攔截controller里的action,並註入我們自己的代碼邏輯,向全局的異常記錄,用戶授權,Url授權,操作行為記錄等,這一大批Lind的基本組件都是實現MVC和API的過濾實現的,使用這些過濾讓我們不用去像HttpModule和HttpHandler那樣,還要在Config里配置註入點,讓程式員在開發方式上感覺很舒服,維護成功很低!

本文主要內容點

  1. Lind.DDD里的方法攔截器
  2. 動態註入需要Lind.DDD.Plugins的支持
  3. 零配置的方法攔截
  4. 一個日誌攔截器
  5. 正在構建一個緩存攔截器

目錄結構

 

Lind.DDD里的方法攔截器

Lind.DDD.Aspects這個攔截器起源自ABP框架,但不知道為什麼,ABP對這個攔截器並沒有完全實現,所以今天大叔又實現了一下,解決了相關BUG, 對方法攔截上,在動態代理工廠里對方法攔截上下文添加了一些必要的參數,因為大叔認為,你只提供一個“方法名稱”參數,太過簡單了,哈哈。

    /// <summary>
    /// 方法相關信息
    /// </summary>
    public class MethodMetadata
    {
        /// <summary>
        /// 上下文
        /// </summary>
        private MethodInfo _context;
        /// <summary>
        /// 方法名
        /// </summary>
        private string _methodName;

        public MethodMetadata(string methodName, MethodInfo context = null)
        {
            _methodName = methodName;
            _context = context;
        }
        /// <summary>
        /// 方法名稱
        /// </summary>
        public virtual string MethodName
        {
            get { return _methodName; }
            set { _methodName = value; }
        }
        /// <summary>
        /// 方法上下文
        /// </summary>
        public virtual string Context
        {
            get { return _context; }
            set { _context = value; }
        }
    }

一個簡單的日誌攔截器的實現,它在方法執行前去攔截

   /// <summary>
    /// 方法執行前攔截,並記錄日誌
    /// </summary>
    public class LoggerAspectAttribute : BeforeAspectAttribute
    {
        public override void Action(InvokeContext context)
        {
            Console.WriteLine("logger start!" + context.Method.MethodName);
            Lind.DDD.Logger.LoggerFactory.Instance.Logger_Info(context.Method.MethodName + "這個方法開始執行");
        }
    }

而在程式中,這個特性Attribute如何被動態代理攔截呢,事件上,如果你直接寫代碼也是可以的,就是使用Aspect提供的ProxyFactory工廠來進行生產,但大叔認為,這樣的代碼耦合度太高,而且對於現有的代碼還需要進行修改,最重要一點,這種代碼總感覺有種壞味道!

     static void Main(string[] args)
        {
            ProxyFactory.CreateProxy<ITest>(typeof(LoggerAspectTest)).Do();
            Console.Read();
        }

所以就有了下麵大叔的封裝,用到了Lind.DDD.Plugins這個插件模式,將所有的攔截器都先進行註冊,然後在生產對象時為它動態添加對應的ProxyFactory對象,請大家接著向下看,動態註入需要Lind.DDD.Plugins的支持這部分講解。

動態註入需要Lind.DDD.Plugins的支持

上面的攔截器只是簡單的實現,簡單的調用,而不具有一般性,即你需要自己維護需要“攔截的代碼”,而大叔在進行使用中感覺很不爽,於是想起了Plugins,讓插件為我們實現這種註入,就像MVC的Filter一樣,在框架本身去實現方法攔截的功能!大叔認為這樣才是最好的!

1 所有攔截器都繼承IAspectProxy表示介面,而它自己則是繼承IPlugins的

 

   /// <summary>
    /// 支持AOP攔截的介面,它被認為是一種插件動態註入到系統中
    /// </summary>
    public interface IAspectProxy : Lind.DDD.Plugins.IPlugins { }

 

2 在PluginManager的Resolve方法中,添加動態的ProxyFactory實現,讓實現了IAspectProxy的類型,自動進行攔截器的實現

      /// <summary>
        /// 從插件容器里返回對象
        /// </summary>
        /// <param name="serviceName">對象全名</param>
        /// <param name="serviceType">介面類型</param>
        /// <returns></returns>
        public static object Resolve(string serviceName, Type serviceType)
        {
            var obj = _container.ResolveNamed(serviceName, serviceType);
            if (typeof(Lind.DDD.Aspects.IAspectProxy).IsAssignableFrom(serviceType))
            {
                obj = ProxyFactory.CreateProxy(serviceType, obj.GetType());
            }
            return obj;
        }

OK,有了上面的代碼,我們的方法攔截就成了一種插件了,在使用的時間之前的插件的使用方法相同,當然底層還是使用autofac來實現的Ioc容器。

 var old = Lind.DDD.Plugins.PluginManager.Resolve<IAopHelloTest2>("Lind.DDD.UnitTest.AopHello");
 old.Hello("zz", 1);

一個日誌攔截器

日誌記錄是一些業務複雜方法必備的,如一些訂單方法,用戶提現方法都會添加相關的日誌,而如果希望動態添加日誌,而不在代碼段中去添加,則可以設計一個日誌攔截器,當然你可以在方法執行前去控制,也可以在方法執行後去控制!

  /// <summary>
    /// 方法執行前攔截,並記錄日誌
    /// </summary>
    public class LoggerAspectAttribute : BeforeAspectAttribute
    {
        public override void Action(InvokeContext context)
        {
            Console.WriteLine("logger start!" + context.Method.MethodName);
            Lind.DDD.Logger.LoggerFactory.Instance.Logger_Info(context.Method.MethodName + "這個方法開始執行");
        }
    }

    /// <summary>
    /// 方法執行完成後攔截,並記錄日誌
    /// </summary>
    public class LoggerEndAspectAttribute : AfterAspectAttribute
    {
        public override void Action(InvokeContext context)
        {
            Console.WriteLine("logger start!" + context.Method.MethodName);
            Lind.DDD.Logger.LoggerFactory.Instance.Logger_Info(context.Method.MethodName + "這個方法開始執行");
        }
    }

目錄方法需要添加這種日誌的行為,只要在方法上添加對應的特性即可,(方法不需要為虛方法)而不需要修改方法代碼體,如下麵的代碼

   /// <summary>
    /// AOP調用方式
    /// </summary>
    public class LoggerAspectTest : ITest
    {
        [LoggerAspectAttribute]
        public void Do()
        {
            //我做事情
            Console.WriteLine("我做事情");
        }
    }

正在構建一個緩存攔截器

目前,大叔正在構建一個緩存的攔截器,主要是實現對方法返回值的緩存,而不需要將這種緩存判斷的邏輯寫在每個方法體內,大叔認為,這種面向切麵的AOP的設計,才是大勢所趨,敬請大家期待!

   /// <summary>
    /// 緩存攔截器
    /// </summary>
    public class CachingAspectAttribute : BeforeAspectAttribute
    {
        CachingMethod cachingMethod;
        public CachingAspectAttribute(CachingMethod cachingMethod)
        {
            this.cachingMethod = cachingMethod;
        }

        public override void Action(InvokeContext context)
        {
            var method = context.Method;
            string prefix = "Lind";
            var baseInterfaces = context.GetType().GetInterfaces();
            if (baseInterfaces != null && baseInterfaces.Any())
            {
                foreach (var item in baseInterfaces)
                {
                    prefix += item.ToString() + "_";
                }
            }

            //鍵名,在put和get時使用
            var key = prefix + method.MethodName;
            Console.WriteLine(key);
            switch (cachingMethod)
            {
                case CachingMethod.Remove:
                    //……
                    break;
                case CachingMethod.Get:
                    //……
                    break;
                case CachingMethod.Put:
                    //……
                    break;
                default:
                    throw new InvalidOperationException("無效的緩存方式。");

            }
        }
    }

我們對支持的追求將不會停止,希望廣大青年都可以踏一心來,去認真的研究一個技術,事實上,對一個技術研究透了,大叔認為就足夠了!

此致

敬禮

回到目錄

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Django基本配置 Python的WEB框架有Django、Tornado、Flask 等多種,Django相較與其他WEB框架其優勢為:大而全,框架本身集成了ORM、模型綁定、模板引擎、緩存、Session等諸多功能 1、安裝 2、創建Django工程 其他命令: mysite目錄結構: Dja ...
  • 1.寫一條sql關聯兩個表要求顯示欄位如下 城市id 城市名稱=name 省份名稱=name select c.id,c.name,p.name from city as c join province as p on c.pid=p.id; 結果: 2.用thinkphp實現 關聯兩個表要求顯示字 ...
  • 博客一:轉載自http://shmilyaw-hotmail-com.iteye.com/blog/1825171 java stack的詳細實現分析 簡介 我們最常用的數據結構之一大概就是stack了。在實際的程式執行,方法調用的過程中都離不開stack。那麼,在一個成熟的類庫裡面,它的實現是怎麼 ...
  • 此篇文章同樣是參考SVNKit在wiki的官方文檔做的demo,每個類都可以單獨運行。具體的細節都寫到註釋里了~ 開發背景: SVNKit版本:1.7.14 附上官網下載鏈接:https://www.svnkit.com/org.tmatesoft.svn_1.7.14.standalone.zip ...
  • 1.demo中最常見的方式是在工程下的web.xml中設置(有時候根據業務可能需要設置action,在action中處理邏輯載入跳轉什麼的,比較少): 2.使用Urlrewrite地址重寫,優點還是挺多的,比如安全性能,具體可以百度下,下麵介紹使用方式: 首先還是導入 urlrewrite 的jar ...
  • 調用同步鎖的wait()、notify()、notifyAll()進行線程通信 看這個經典的存取款問題,要求兩個線程存款,兩個線程取款,賬戶里有餘額的時候只能取款,沒餘額的時候只能存款,存取款金額相同。相當於存取款交替進行,金額相同。 線程間通信,需要通過同一個同步監視器(也就是this或者顯式的O ...
  • 前言 日誌是非常重要的,最近有接觸到這個,所以系統的看一下Python這個模塊的用法。本文即為Logging模塊的用法簡介,主要參考文章為Python官方文檔,鏈接見參考列表。 另外,Python的 "HOWTOs文檔" 很詳細,連日誌該怎麼用都寫了,所以有英文閱讀能力的同學建議去閱讀一下。 Log ...
  • 1.安裝依賴包 2、安裝boost庫(對應版本高於或低於這個版本都有問題) 3、添加mysql用戶組 4、下載mysql源碼包並安裝 5.調整配置文件 6. 給安裝目錄設置許可權 7.初始化資料庫 註:初始化後會生成預設密碼,請記錄下來2016-02-17T03:16:36.869627Z 1 [No ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...