Aop動態生成代理類時支持帶參數構造函數

1、背景html

  在某些狀況下,咱們須要植入AOP代碼的類並無默認構造函數。那麼此時動態生成的代理類也須要相同簽名的構造函數,而且內部調用原始類的構造函數。本身折騰了1晚上沒搞定,如今搞定了發出來供你們一塊兒學習探討。程序員

 

2、梳理功能點微信

  在已支持經過默認構造函數進行AOP代碼植入的狀況下(之前發過一篇博文,傳送門:你們一塊兒Aop),實現該功能咱們須要作的是:架構

  1.如何經過獲取原始類的構造函數參數列表,並使用Emit生成代理類的相應構造函數。分佈式

  2.如何建立並保存實例化代理類的委託,加快實例化速度。ide

 

3、實現方案函數

  功能1:學習

  在原來的生成代理類,代理類中的方法處增長生成構造函數的代碼。代碼很簡單,以下:  測試

 1             if (_parameters == null || _parameters.Length == 0)
 2             {
 3                 return typeBuilder;
 4             }
 5 
 6             var baseConstructor = _originalType.GetConstructor(_parameterTypes);
 7             if (baseConstructor == null)
 8                 throw new MissingMethodException("未找到相應參數的構造函數");
 9 
10             const MethodAttributes METHOD_ATTRIBUTES = MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName | MethodAttributes.Public;
11             var constructor = typeBuilder.DefineConstructor(METHOD_ATTRIBUTES, CallingConventions.HasThis, _parameterTypes);
12 
13             var il = constructor.GetILGenerator();
14 
15             il.Emit(OpCodes.Ldarg_0);
16 
17             for (int i = 1; i <= _parameters.Length; i++)  //這裏要注意下,索引爲0的參數是當前對象自己 18             {
19                 il.Emit(OpCodes.Ldarg, i);
20             }
21 
22             il.Emit(OpCodes.Call, baseConstructor);
23             il.Emit(OpCodes.Ret);
24 
25             return typeBuilder;

  其中要注意2點,ui

  ①定義構造函數的時候須要指定MethodAttributes,日常咱們代碼編寫的公有構造函數就是上面寫的4個。

  ②由於咱們定義的是構造函數,因此此處必須指定CallingConventions.HasThis。至於爲何去看msdn的解釋,不在咱們本次討論範圍內。

  

  到這裏咱們的動態類的構造已經完成了,接下去解決功能2:

  這裏只要在原先直接取默認構造函數的地方增長一個判斷,獲取指定參數的構造函數來構造委託。下面貼代碼:

 1         private DynamicMethod GetConstructorMethod<TReturnType>(Type aopType)
 2         {
 3             var method = _parameters == null || _parameters.Length == 0
 4                         ? new DynamicMethod("", typeof(TReturnType), null)
 5                         : new DynamicMethod("", typeof(TReturnType), _parameterTypes);
 6 
 7             var il = method.GetILGenerator();
 8 
 9             BuildConstructorIl(il, aopType);
10 
11             return method;
12         }
13  
14  
15          private void BuildConstructorIl(ILGenerator il, Type aopType)
16          {
17              if (_parameters == null || _parameters.Length == 0)
18              {
19                  ConstructorInfo info = aopType.GetConstructor(Type.EmptyTypes);
20                  if (info == null)
21                      return;
22  
23                  il.Emit(OpCodes.Newobj, info);
24                  il.Emit(OpCodes.Ret);
25              }
26              else
27              {
28                  ConstructorInfo info = aopType.GetConstructor(_parameterTypes);
29                  if (info == null)
30                      return;
31  
32                  var localInstance = il.DeclareLocal(aopType);
33                  for (int i = 0; i < _parameterTypes.Length; i++) //這裏與上面的標紅不一樣,這裏由於是直接定義了一個方法,而且不存在實例,因此此處參數從索引0開始
34                      il.Emit(OpCodes.Ldarg, i);
35  
36                  il.Emit(OpCodes.Newobj, info);
37  
38                  il.Emit(OpCodes.Stloc, localInstance);
39                  il.Emit(OpCodes.Ldloc, localInstance);
40                  il.Emit(OpCodes.Ret);
41              }
42          }

  這裏須要的注意的點已經標紅出來了。但這裏僅是核心代碼,在外層再封裝幾個重載用於生成不一樣的Func<>。

 1         public Func<TReturnType> CreateFunc<TReturnType>(Type aopType)
 2         {
 3             var method = GetConstructorMethod<TReturnType>(aopType);
 4 
 5             return method.CreateDelegate(typeof(Func<TReturnType>)) as Func<TReturnType>;
 6         }
 7 
 8         public Func<TP1, TReturnType> CreateFunc<TP1, TReturnType>(Type aopType)
 9         {
10             var method = GetConstructorMethod<TReturnType>(aopType);
11 
12             return method.CreateDelegate(typeof(Func<TP1, TReturnType>)) as Func<TP1, TReturnType>;
13         }
14 
15         public Func<TP1, TP2, TReturnType> CreateFunc<TP1, TP2, TReturnType>(Type aopType)
16         {
17             var method = GetConstructorMethod<TReturnType>(aopType);
18 
19             return method.CreateDelegate(typeof(Func<TP1, TP2, TReturnType>)) as Func<TP1, TP2, TReturnType>;
20         }

大功告成~,再進行一些簡單的重構。測試效果:

4、收尾

  源碼附上:源碼+Demo在此!

  以爲有用記得點贊哦~

 

做者:  Zachary
出處:https://zacharyfan.com/archives/89.html

 

 

▶關於做者:張帆(Zachary,我的微信號:Zachary-ZF)。堅持用心打磨每一篇高質量原創。歡迎掃描右側的二維碼~。

按期發表原創內容:架構設計丨分佈式系統丨產品丨運營丨一些思考。

 

若是你是初級程序員,想提高但不知道如何下手。又或者作程序員多年,陷入了一些瓶頸想拓寬一下視野。歡迎關注個人公衆號「跨界架構師」,回覆「技術」,送你一份我長期收集和整理的思惟導圖。

若是你是運營,面對不斷變化的市場一籌莫展。又或者想了解主流的運營策略,以豐富本身的「倉庫」。歡迎關注個人公衆號「跨界架構師」,回覆「運營」,送你一份我長期收集和整理的思惟導圖。

相關文章
相關標籤/搜索