<ul id="qxxfc"><fieldset id="qxxfc"><tr id="qxxfc"></tr></fieldset></ul>


      動態(tài)代理配合rpc技術(shù)調(diào)用遠程服務(wù),不用關(guān)注細節(jié)的實現(xiàn),讓程序就像在本地調(diào)用以用。


      因此動態(tài)代理在微服務(wù)系統(tǒng)中是不可或缺的一個技術(shù)。網(wǎng)上看到大部分案例都是通過反射自己實現(xiàn),且相當復(fù)雜。編寫和調(diào)試相當不易,我這里提供里一種簡便的方式來實現(xiàn)動態(tài)代理。

      1、創(chuàng)建我們的空白.netcore項目?

      通過vs2017輕易的創(chuàng)建出一個.netcore項目

      2、編寫Startup.cs文件

      默認Startup 沒有構(gòu)造函數(shù),自行添加構(gòu)造函數(shù),帶有??IConfiguration 參數(shù)的,用于獲取項目配置,但我們的示例中未使用配置
      public Startup(IConfiguration configuration) { Configuration = configuration;
      //注冊編碼提供程序 Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); }
      在ConfigureServices 配置日志模塊,目前core更新的很快,日志的配置方式和原來又很大出入,最新的配置方式如下
      // For more information on how to configure your application, visit
      https://go.microsoft.com/fwlink/?LinkID=398940 public void
      ConfigureServices(IServiceCollection services ) {
      services.AddLogging(loggingBuilder=> {
      loggingBuilder.AddConfiguration(Configuration.GetSection("Logging"));
      loggingBuilder.AddConsole(); loggingBuilder.AddDebug(); }); }
      添加路由過濾器,監(jiān)控一個地址,用于調(diào)用我們的測試代碼。netcore默認沒有UTF8的編碼方式,所以要先解決UTF8編碼問題,否則將在輸出中文時候亂碼。

      這里注意?Map? 內(nèi)部傳遞了參數(shù)?applicationBuilder ,千萬不要 使用Configure(IApplicationBuilder
      app, IHostingEnvironment env )
      中的app參數(shù),否則每次請求api/health時候都將調(diào)用這個中間件(app.Run會短路期后邊所有的中間件),
      app.Map("/api/health", (applicationBuilder) => {
      applicationBuilder.Run(context=> { return
      context.Response.WriteAsync(uName.Result, Encoding.UTF8); }); });
      ?

      3、代理

      netcore 已經(jīng)為我們完成了一些工作,提供了DispatchProxy 這個類
      #region 程序集 System.Reflection.DispatchProxy, Version=4.0.4.0, Culture=neutral,
      PublicKeyToken=b03f5f7f11d50a3a// C:\Program
      Files\dotnet\sdk\NuGetFallbackFolder\microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Reflection.DispatchProxy.dll
      #endregion namespace System.Reflection { // public abstract class DispatchProxy
      {// protected DispatchProxy(); // // 類型參數(shù): // T: // // TProxy: public static T
      Create<T, TProxy>()where TProxy : DispatchProxy; // // 參數(shù): // targetMethod: //
      // args: protected abstract object Invoke(MethodInfo targetMethod, object[]
      args); } } View Code
      這個類提供了一個實例方法,一個靜態(tài)方法:

      Invoke(MethodInfo targetMethod, object[] args) (注解1)


      Create<T, TProxy>()(注解2)

      Create 創(chuàng)建代理的實例對象,實例對象在調(diào)用方法時候會自動執(zhí)行Invoke

      ?

      ?

      首先我們創(chuàng)建一個動態(tài)代理類??ProxyDecorator<T>:DispatchProxy? 需要繼承DispatchProxy? 。

      在DispatchProxy 的靜態(tài)方法??Create<T, TProxy>()中要求?TProxy : DispatchProxy

      ProxyDecorator 重寫??DispatchProxy的虛方法invoke?

      我們可以在ProxyDecorator 類中添加一些其他方法,比如:異常處理,MethodInfo執(zhí)行前后的處理。

      重點要講一下?

      ProxyDecorator 中需要傳遞一個 T類型的變量?decorated 。

      因為??DispatchProxy.Create<T, ProxyDecorator<T>>(); 會創(chuàng)建一個新的T的實例對象?,
      這個對象是代理對象實例,我們將?decorated 綁定到這個代理實例上

      接下來這個代理實例在執(zhí)行T類型的任何方法時候都會用到?decorated,因為 [decorated]
      會被傳給??targetMethod.Invoke(decorated, args)? ?(targetMethod 來自注解1) ,invoke相當于執(zhí)行

      這樣說的不是很明白,我們直接看代碼
      1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4
      using System.Linq.Expressions; 5 using System.Reflection; 6 using System.Text;
      7 using System.Threading.Tasks; 8 9 namespace TestWFW 10 { 11 public class
      ProxyDecorator<T> : DispatchProxy 12 { 13 //關(guān)鍵詞 RealProxy 14 private T
      decorated; 15 private event Action<MethodInfo, object[]> _afterAction; //動作之后執(zhí)行
      16 private event Action<MethodInfo, object[]> _beforeAction; //動作之前執(zhí)行 17 18
      //其他自定義屬性,事件和方法 19 public ProxyDecorator() 20 { 21 22 } 23 24 25 ///
      <summary> 26 /// 創(chuàng)建代理實例 27 /// </summary> 28 /// <param name="decorated">
      代理的接口類型</param> 29 /// <returns></returns> 30 public T Create(T decorated) 31
      { 32 33 object proxy = Create<T, ProxyDecorator<T>>(); //調(diào)用DispatchProxy
      的Create 創(chuàng)建一個新的T 34 ((ProxyDecorator<T>)proxy).decorated = decorated;
      //這里必須這樣賦值,會自動未proxy 添加一個新的屬性
                                                  //其他的請如法炮制 35

                return (T)proxy; 36 } 37 38 /// <summary> 39 /// 創(chuàng)建代理實例 40 ///
      </summary> 41 /// <param name="decorated">代理的接口類型</param> 42 /// <param
      name="beforeAction">方法執(zhí)行前執(zhí)行的事件</param> 43 /// <param name="afterAction">
      方法執(zhí)行后執(zhí)行的事件</param> 44 /// <returns></returns> 45 public T Create(T decorated,
      Action<MethodInfo,object[]> beforeAction, Action<MethodInfo, object[]>
      afterAction) 46 { 47 48 object proxy = Create<T, ProxyDecorator<T>>(); //
      調(diào)用DispatchProxy 的Create 創(chuàng)建一個新的T 49 ((ProxyDecorator<T>)proxy).decorated =
      decorated; 50 ((ProxyDecorator<T>)proxy)._afterAction = afterAction; 51
      ((ProxyDecorator<T>)proxy)._beforeAction = beforeAction; 52 //
      ((GenericDecorator<T>)proxy)._loggingScheduler =
      TaskScheduler.FromCurrentSynchronizationContext(); 53 return (T)proxy; 54 }
      55 56 57 58 protected override object Invoke(MethodInfo targetMethod, object
      [] args) 59 { 60 if (targetMethod == null) throw new Exception("無效的方法"); 61
      62 try 63 { 64 //_beforeAction 事件 65 if (_beforeAction != null) 66 { 67
      this._beforeAction(targetMethod, args); 68 } 69 70 71 object result =
      targetMethod.Invoke(decorated, args); 72 ? ?
      ?        System.Diagnostics.Debug.WriteLine(result);      //打印輸出面板 73 var
      resultTask = resultas Task; 74 if (resultTask != null) 75 { 76
      resultTask.ContinueWith(task =>//ContinueWith 創(chuàng)建一個延續(xù),該延續(xù)接收調(diào)用方提供的狀態(tài)信息并執(zhí)行 當目標系統(tǒng)
      tasks。 77 { 78 if (task.Exception != null) 79 { 80
      LogException(task.Exception.InnerException ?? task.Exception, targetMethod); 81
      } 82 else 83 { 84 object taskResult = null; 85 if
      (task.GetType().GetTypeInfo().IsGenericType && 86
      task.GetType().GetGenericTypeDefinition() ==typeof(Task<>)) 87 { 88 var
      property = task.GetType().GetTypeInfo().GetProperties().FirstOrDefault(p =>
      p.Name =="Result"); 89 if (property != null) 90 { 91 taskResult =
      property.GetValue(task); 92 } 93 } 94 if (_afterAction != null) 95 { 96
      this._afterAction(targetMethod, args); 97 } 98 } 99 }); 100 } 101 else
      102 { 103 try 104 { 105 // _afterAction 事件 106 if (_afterAction != null) 107
      {108 this._afterAction(targetMethod, args); 109 } 110 } 111 catch (Exception
      ex)112 { 113 //Do not stop method execution if exception 114 LogException(ex);
      115 } 116 } 117 118 return result; 119 } 120 catch (Exception ex) 121 { 122
      if (ex is TargetInvocationException) 123 { 124 LogException(ex.InnerException
      ?? ex, targetMethod); 125 throw ex.InnerException ?? ex; 126 } 127 else 128 {
      129 throw ex; 130 } 131 } 132 133 } 134 135 136 /// <summary> 137 ///
      aop異常的處理138 /// </summary> 139 /// <param name="exception"></param> 140 ///
      <param name="methodInfo"></param> 141 private void LogException(Exception
      exception, MethodInfo methodInfo =null) 142 { 143 try 144 { 145 var
      errorMessage =new StringBuilder(); 146 errorMessage.AppendLine($"Class
      {decorated.GetType().FullName}"); 147 errorMessage.AppendLine($"Method
      {methodInfo?.Name} threw exception"); 148
      errorMessage.AppendLine(exception.Message);149 150 //
      _logError?.Invoke(errorMessage.ToString()); 記錄到文件系統(tǒng) 151 } 152 catch (Exception)
      153 { 154 // ignored 155 //Method should return original exception 156 } 157
      }158 } 159 }
      ?

      代碼比較簡單,相信大家都看的懂,關(guān)鍵的代碼和核心的系統(tǒng)代碼已經(jīng)加粗和加加粗+紅 標注出來了

      DispatchProxy<T> 類中有兩種創(chuàng)建代理實例的方法

      我們看一下第一種比較簡單的創(chuàng)建方法
      // This method gets called by the runtime. Use this method to configure the
      HTTP request pipeline. public void Configure(IApplicationBuilder app,
      IHostingEnvironment env ) {if (env.IsDevelopment()) {
      app.UseDeveloperExceptionPage(); }// 添加健康檢查路由地址 app.Map("/api/health",
      (applicationBuilder) => { applicationBuilder.Run(context => { IUserService
      userService= new UserService(); //執(zhí)行代理 var serviceProxy = new
      ProxyDecorator<IUserService>(); IUserService user =
      serviceProxy.Create(userService);// Task<string> uName = user.GetUserName(222);
      context.Response.ContentType= "text/plain;charset=utf-8"; return
      context.Response.WriteAsync(uName.Result, Encoding.UTF8); }); }); }
      代碼中 UserService 和 IUserService 是一個class和interface? 自己實現(xiàn)即可
      ,隨便寫一個接口,并用類實現(xiàn),任何一個方法就行,下面只是演示調(diào)用方法時候會執(zhí)行什么,這個方法本身在巖石中并不重要。

      ?由于ProxyDecorator 中并未注入相關(guān)事件,所以我們在調(diào)用 user.GetUserName(222)
      時候看不到任何特別的輸出。下面我們演示一個相對復(fù)雜的調(diào)用方式。
      // 添加健康檢查路由地址 app.Map("/api/health2", (applicationBuilder) => {
      applicationBuilder.Run(context=> { IUserService userService = new UserService();
      //執(zhí)行代理 var serviceProxy = new ProxyDecorator<IUserService>(); IUserService user
      = serviceProxy.Create(userService, beforeEvent, afterEvent);// Task<string>
      uName = user.GetUserName(222); context.Response.ContentType = "
      text/plain;charset=utf-8"; return context.Response.WriteAsync(uName.Result,
      Encoding.UTF8); }); });
      ?
      IUserService user = serviceProxy.Create(userService, beforeEvent,
      afterEvent); 在創(chuàng)建代理實例時候傳遞了beforEvent 和 afterEvent,這兩個事件處理
      函數(shù)是我們在業(yè)務(wù)中定義的
      void beforeEvent(MethodInfo methodInfo, object[] arges)
      {
      System.Diagnostics.Debug.WriteLine("方法執(zhí)行前");
      }

      void afterEvent(MethodInfo methodInfo, object[] arges)
      {
      System.Diagnostics.Debug.WriteLine("執(zhí)行后的事件");
      }

      在代理實例執(zhí)行接口的任何方法的時候都會執(zhí)行? beforeEvent,和 afterEvent 這兩個事件(請參考Invoke(MethodInfo
      targetMethod, object[] args) 方法的實現(xiàn))

      在我們的示例中將會在vs的 輸出 面板中看到?

      ?

      ?

      方法執(zhí)行前

      “方法輸出的值”

      執(zhí)行后事件

      我們看下運行效果圖:

      ?

      ?

      ?

      ?這是?user.GetUserName(222) 的運行結(jié)果



      ?

      ?

      ?控制臺輸出結(jié)果

      ?

      友情鏈接
      ioDraw流程圖
      API參考文檔
      OK工具箱
      云服務(wù)器優(yōu)惠
      阿里云優(yōu)惠券
      騰訊云優(yōu)惠券
      京東云優(yōu)惠券
      站點信息
      問題反饋
      郵箱:[email protected]
      QQ群:637538335
      關(guān)注微信

        <ul id="qxxfc"><fieldset id="qxxfc"><tr id="qxxfc"></tr></fieldset></ul>
          三级黄色生活片 | 日韩精品高线在线观看 | 精品久久国产字幕高潮 | 开心激情网深爱五月天 | 操欧美浪逼视屏 | 亚洲图色色 | 人人爱人人草 | 一级特黄录像免费看 | 日韩深夜视频 | 男人日女人的视频软件 |