net core天馬行空系列: 一個介面多個實現類,利用mixin技術通過自定義服務名,實現精準屬性注入

  • 2019 年 10 月 3 日
  • 筆記

系列目錄

1.net core天馬行空系列:原生DI+AOP實現spring boot註解式編程

2.net core天馬行空系列: 泛型倉儲和聲明式事物實現最優雅的crud操作

       哈哈哈哈,大家好,我就是高產似母豬的三合。日常開發中,我們常會遇到這樣的場景,一個介面,有多個實現類,在某個業務中,我們希望指定某個實現類,如今網路上常見的解決方案,就是注入一個委託或者利用工廠模式,這些方式雖然能實現功能,但使用起來還是不夠優雅,如何才稱得上優雅呢?自然是在添加服務的時候給服務指定名稱,注入的時候根據名稱來進行注入,沒錯,就是類似spring boot里的@Qualifier註解,那麼net core能實現這個註解么?要知道net core里的原生DI並不支援在註冊的時候給服務添加名稱,所以實現起來也是難上加難,但是,利用動態代理,我們就能完美解決這個問題,沒錯,他Lei了,net core版[QualifierAttribute],實現這個註解用到的最核心的技術,就是動態代理中非常重要的mixin,什麼是mixin呢?玩過less的小夥伴可能會知道,這玩意可以把2個css樣式混合成一個,而在net core中,DP(castle.dynamicproxy)提供的mixin技術,可以在程式運行時,把多個類混合成一個動態代理類,這個混合類既可以用作類1,又可以用作類2,那麼思路就很清晰了,類1就是我們注入的服務類,類2需要我們自定義,在我們的這個自定義類中,我們可以添加一個Name的屬性,這樣在註冊服務的時候給服務命名,到了注入的時候,我們就可以根據名稱來進行精準地的屬性注入。BTW,動態代理,註解式編程,AOP貫穿本系列始終,no bb,正文開始。

1.定義用到的類

定義QualifierAttribute註解

 public class QualifierAttribute : Attribute      {          public string Name { get; }            public QualifierAttribute(string name)          {              if (string.IsNullOrWhiteSpace(name))              {                  throw new ArgumentException("服務名稱不能為空");              }                this.Name = name;          }      }

定義用來進行混合的附加類介面IDependencyAddition和他的實現類DependencyAddition,類裡面只有一個名稱的屬性。

public interface IDependencyAddition      {          string Name { set; get; }      }
 public class DependencyAddition : IDependencyAddition      {          public string Name { set; get; }      }

第一篇文章里,講過有一輛汽車,汽車裡有引擎,我們在這基礎上進行擴展,汽車總是有輪胎的,我們定義一個輪胎介面IWheel和他的2個實現類WheelA和WheelB,類里只有一個Scroll方法,表示輪胎在滾,同時向控制台輸出他們是哪種輪胎。

 public interface IWheel      {          void Scroll();      }
  public class WheelA : IWheel      {          public void Scroll()          {              Console.WriteLine("我是A輪胎,我正在滾");          }      }
 public class WheelB : IWheel      {          public void Scroll()          {              Console.WriteLine("我是B輪胎,我正在滾");          }      }

修改汽車類介面ICar和他的實現類Car,主要就是添加了輪胎的屬性注入,並且用[Qualifier("B輪胎")]註解指定使用哪種輪胎,然後調用Scroll方法,讓輪胎滾起來。

   public interface ICar      {          Engine Engine { set; get; }            IWheel Wheel { set; get; }            void Fire();      }
   public class Car : ICar      {          [Autowired]          public Engine Engine { set; get; }            [Value("oilNo")]          public int OilNo { set; get; }            [Autowired]          [Qualifier("B輪胎")]          public IWheel Wheel { set; get; }            [Transactional]          public void Fire()          {              Console.WriteLine("加滿" + OilNo + "號汽油,點火");                Wheel.Scroll();                Engine.Start();          }      }

IServiceCollection的靜態擴展類SummerBootExtentions,和上一篇相比,主要是添加了AddSbService的新重載,使註冊服務的時候能夠為服務添加名稱,在這基礎上進一步封裝了AddSbSingleton,AddSbScoped和AddSbTransient方法。還有在工廠委託函數里進行屬性注入的時候,添加了支援[QualifierAttribute]註解的邏輯,完整類程式碼如下:

public static class SummerBootExtentions      {          /// <summary>          /// 瞬時          /// </summary>          /// <typeparam name="TService"></typeparam>          /// <typeparam name="TImplementation"></typeparam>          /// <param name="services"></param>          /// <param name="interceptorTypes"></param>          /// <returns></returns>          public static IServiceCollection AddSbTransient<TService, TImplementation>(this IServiceCollection services, params Type[] interceptorTypes)          {              return services.AddSbService(typeof(TService), typeof(TImplementation), ServiceLifetime.Transient, interceptorTypes);          }            /// <summary>          /// 瞬時          /// </summary>          /// <param name="services"></param>          /// <param name="serviceType"></param>          /// <param name="implementationType"></param>          /// <param name="interceptorTypes"></param>          /// <returns></returns>          public static IServiceCollection AddSbTransient(this IServiceCollection services, Type serviceType,              Type implementationType, params Type[] interceptorTypes)          {              return services.AddSbService(serviceType, implementationType, ServiceLifetime.Transient, interceptorTypes);          }            /// <summary>          /// 請求級別          /// </summary>          /// <typeparam name="TService"></typeparam>          /// <typeparam name="TImplementation"></typeparam>          /// <param name="services"></param>          /// <param name="interceptorTypes"></param>          /// <returns></returns>          public static IServiceCollection AddSbScoped<TService, TImplementation>(this IServiceCollection services, params Type[] interceptorTypes)          {              return services.AddSbService(typeof(TService), typeof(TImplementation), ServiceLifetime.Scoped, interceptorTypes);          }            /// <summary>          /// 請求級別          /// </summary>          /// <param name="services"></param>          /// <param name="serviceType"></param>          /// <param name="implementationType"></param>          /// <param name="interceptorTypes"></param>          /// <returns></returns>          public static IServiceCollection AddSbScoped(this IServiceCollection services, Type serviceType,              Type implementationType, params Type[] interceptorTypes)          {              return services.AddSbService(serviceType, implementationType, ServiceLifetime.Scoped, interceptorTypes);          }            /// <summary>          /// 單例          /// </summary>          /// <typeparam name="TService"></typeparam>          /// <typeparam name="TImplementation"></typeparam>          /// <param name="services"></param>          /// <param name="interceptorTypes"></param>          /// <returns></returns>          public static IServiceCollection AddSbSingleton<TService, TImplementation>(this IServiceCollection services, params Type[] interceptorTypes)          {              return services.AddSbService(typeof(TService), typeof(TImplementation), ServiceLifetime.Singleton, interceptorTypes);          }            /// <summary>          /// 單例          /// </summary>          /// <param name="services"></param>          /// <param name="serviceType"></param>          /// <param name="implementationType"></param>          /// <param name="interceptorTypes"></param>          /// <returns></returns>          public static IServiceCollection AddSbSingleton(this IServiceCollection services, Type serviceType,              Type implementationType, params Type[] interceptorTypes)          {              return services.AddSbService(serviceType, implementationType, ServiceLifetime.Singleton, interceptorTypes);          }            public static IServiceCollection AddSbService(this IServiceCollection services, Type serviceType, Type implementationType,              ServiceLifetime lifetime, params Type[] interceptorTypes)          {              services.Add(new ServiceDescriptor(implementationType, implementationType, lifetime));                object Factory(IServiceProvider provider)              {                  var target = provider.GetService(implementationType);                  var properties = implementationType.GetTypeInfo().DeclaredProperties;                    foreach (PropertyInfo info in properties)                  {                      //屬性注入                      if (info.GetCustomAttribute<AutowiredAttribute>() != null)                      {                          var propertyType = info.PropertyType;                          object impl = null;                          var qualifierAttribute = info.GetCustomAttribute<QualifierAttribute>();                          if (qualifierAttribute != null)                          {                              var serviceName = qualifierAttribute.Name;                              var implList = provider.GetServices(propertyType);                              foreach (var tmpImpl in implList)                              {                                  if (ProxyUtil.IsProxy(tmpImpl))                                  {                                      var addition = tmpImpl as IDependencyAddition;                                      if (addition?.Name == serviceName)                                      {                                          impl = tmpImpl;                                          break; ;                                      }                                  }                              }                          }                          else                          {                              impl = provider.GetService(propertyType);                          }                            if (impl != null)                          {                              info.SetValue(target, impl);                          }                      }                        //配置值注入                      if (info.GetCustomAttribute<ValueAttribute>() is ValueAttribute valueAttribute)                      {                          var value = valueAttribute.Value;                          if (provider.GetService(typeof(IConfiguration)) is IConfiguration configService)                          {                              var pathValue = configService.GetSection(value).Value;                              if (pathValue != null)                              {                                  var pathV = Convert.ChangeType(pathValue, info.PropertyType);                                  info.SetValue(target, pathV);                              }                          }                        }                  }                    List<IInterceptor> interceptors = interceptorTypes.ToList()                      .ConvertAll<IInterceptor>(interceptorType => provider.GetService(interceptorType) as IInterceptor);                    var proxyGenerator = provider.GetService<ProxyGenerator>();                  var proxy = proxyGenerator.CreateInterfaceProxyWithTarget(serviceType, target, interceptors.ToArray());                    return proxy;              };                var serviceDescriptor = new ServiceDescriptor(serviceType, Factory, lifetime);              services.Add(serviceDescriptor);                return services;          }            /// <summary>          /// 瞬時          /// </summary>          /// <typeparam name="TService"></typeparam>          /// <param name="services"></param>          /// <param name="interceptorTypes"></param>          /// <returns></returns>          public static IServiceCollection AddSbTransient<TService>(this IServiceCollection services, params Type[] interceptorTypes)          {              return services.AddSbService(typeof(TService), ServiceLifetime.Transient, interceptorTypes);          }            /// <summary>          /// 瞬時          /// </summary>          /// <param name="services"></param>          /// <param name="serviceType"></param>          /// <param name="interceptorTypes"></param>          /// <returns></returns>          public static IServiceCollection AddSbTransient(this IServiceCollection services, Type serviceType, params Type[] interceptorTypes)          {              return services.AddSbService(serviceType, ServiceLifetime.Transient, interceptorTypes);          }            /// <summary>          /// 請求          /// </summary>          /// <typeparam name="TService"></typeparam>          /// <param name="services"></param>          /// <param name="interceptorTypes"></param>          /// <returns></returns>          public static IServiceCollection AddSbScoped<TService>(this IServiceCollection services, params Type[] interceptorTypes)          {              return services.AddSbService(typeof(TService), ServiceLifetime.Scoped, interceptorTypes);          }            /// <summary>          /// 請求          /// </summary>          /// <param name="services"></param>          /// <param name="serviceType"></param>          /// <param name="interceptorTypes"></param>          /// <returns></returns>          public static IServiceCollection AddSbScoped(this IServiceCollection services, Type serviceType,               params Type[] interceptorTypes)          {              return services.AddSbService(serviceType, ServiceLifetime.Scoped, interceptorTypes);          }            /// <summary>          /// 單例          /// </summary>          /// <typeparam name="TService"></typeparam>          /// <param name="services"></param>          /// <param name="interceptorTypes"></param>          /// <returns></returns>          public static IServiceCollection AddSbSingleton<TService>(this IServiceCollection services, params Type[] interceptorTypes)          {              return services.AddSbService(typeof(TService), ServiceLifetime.Singleton, interceptorTypes);          }            /// <summary>          /// 單例          /// </summary>          /// <param name="services"></param>          /// <param name="serviceType"></param>          /// <param name="interceptorTypes"></param>          /// <returns></returns>          public static IServiceCollection AddSbSingleton(this IServiceCollection services, Type serviceType, params Type[] interceptorTypes)          {              return services.AddSbService(serviceType, ServiceLifetime.Singleton, interceptorTypes);          }            public static IServiceCollection AddSbService(this IServiceCollection services, Type serviceType,              ServiceLifetime lifetime, params Type[] interceptorTypes)          {              if (services == null)                  throw new ArgumentNullException(nameof(services));              if (serviceType == (Type)null)                  throw new ArgumentNullException(nameof(serviceType));                object Factory(IServiceProvider provider)              {                  List<IInterceptor> interceptors = interceptorTypes.ToList()                      .ConvertAll<IInterceptor>(interceptorType => provider.GetService(interceptorType) as IInterceptor);                    var proxyGenerator = provider.GetService<ProxyGenerator>();                    var proxy = proxyGenerator.CreateClassProxy(serviceType, interceptors.ToArray());                    var properties = serviceType.GetTypeInfo().DeclaredProperties;                    foreach (PropertyInfo info in properties)                  {                      //屬性注入                      if (info.GetCustomAttribute<AutowiredAttribute>() != null)                      {                          var propertyType = info.PropertyType;                          object impl = null;                          var qualifierAttribute = info.GetCustomAttribute<QualifierAttribute>();                          if (qualifierAttribute != null)                          {                              var serviceName = qualifierAttribute.Name;                              var implList = provider.GetServices(propertyType);                              foreach (var tmpImpl in implList)                              {                                  if (ProxyUtil.IsProxy(tmpImpl))                                  {                                      var addition = tmpImpl as IDependencyAddition;                                      if (addition?.Name == serviceName)                                      {                                          impl = tmpImpl;                                          break; ;                                      }                                  }                              }                          }                          else                          {                              impl = provider.GetService(propertyType);                          }                            if (impl != null)                          {                              info.SetValue(proxy, impl);                          }                      }                      //配置值注入                      if (info.GetCustomAttribute<ValueAttribute>() is ValueAttribute valueAttribute)                      {                          var value = valueAttribute.Value;                          if (provider.GetService(typeof(IConfiguration)) is IConfiguration configService)                          {                              var pathValue = configService.GetSection(value).Value;                              if (pathValue != null)                              {                                  var pathV = Convert.ChangeType(pathValue, info.PropertyType);                                  info.SetValue(proxy, pathV);                              }                          }                      }                  }                    return proxy;              };                var serviceDescriptor = new ServiceDescriptor(serviceType, Factory, lifetime);              services.Add(serviceDescriptor);                return services;          }            /// <summary>          /// 添加summer boot擴展          /// </summary>          /// <param name="builder"></param>          /// <returns></returns>          public static IMvcBuilder AddSB(this IMvcBuilder builder)          {              if (builder == null)                  throw new ArgumentNullException(nameof(builder));              ControllerFeature feature = new ControllerFeature();              builder.PartManager.PopulateFeature<ControllerFeature>(feature);              foreach (Type type in feature.Controllers.Select<TypeInfo, Type>((Func<TypeInfo, Type>)(c => c.AsType())))                  builder.Services.TryAddTransient(type, type);              builder.Services.Replace(ServiceDescriptor.Transient<IControllerActivator, SbControllerActivator>());                return builder;          }            public static IServiceCollection AddSbRepositoryService(this IServiceCollection services, params Type[] interceptorTypes)          {              var types = AppDomain.CurrentDomain.GetAssemblies().SelectMany(it => it.GetTypes());                var tableType = types.Where(it => it.GetCustomAttribute<TableAttribute>() != null);                foreach (var type in tableType)              {                  var injectServiceType = typeof(IRepository<>).MakeGenericType(type);                  var injectImplType = typeof(BaseRepository<>).MakeGenericType(type);                  services.AddSbScoped(injectServiceType, injectImplType, interceptorTypes);              }                return services;          }            /// <summary>          /// 瞬時          /// </summary>          /// <typeparam name="TService"></typeparam>          /// <typeparam name="TImplementation"></typeparam>          /// <param name="services"></param>          /// <param name="name"></param>          /// <param name="interceptorTypes"></param>          /// <returns></returns>          public static IServiceCollection AddSbTransient<TService, TImplementation>(this IServiceCollection services, string name = "", params Type[] interceptorTypes)          {              return services.AddSbService(typeof(TService), typeof(TImplementation), ServiceLifetime.Transient, name, interceptorTypes);          }            /// <summary>          /// 瞬時          /// </summary>          /// <param name="services"></param>          /// <param name="serviceType"></param>          /// <param name="implementationType"></param>          /// <param name="name"></param>          /// <param name="interceptorTypes"></param>          /// <returns></returns>          public static IServiceCollection AddSbTransient(this IServiceCollection services, Type serviceType,              Type implementationType, string name = "", params Type[] interceptorTypes)          {              return services.AddSbService(serviceType, implementationType, ServiceLifetime.Transient, name, interceptorTypes);          }            /// <summary>          /// 請求級別          /// </summary>          /// <typeparam name="TService"></typeparam>          /// <typeparam name="TImplementation"></typeparam>          /// <param name="services"></param>          /// <param name="name"></param>          /// <param name="interceptorTypes"></param>          /// <returns></returns>          public static IServiceCollection AddSbScoped<TService, TImplementation>(this IServiceCollection services, string name = "", params Type[] interceptorTypes)          {              return services.AddSbService(typeof(TService), typeof(TImplementation), ServiceLifetime.Scoped, name, interceptorTypes);          }            /// <summary>          /// 請求級別          /// </summary>          /// <param name="services"></param>          /// <param name="serviceType"></param>          /// <param name="implementationType"></param>          /// <param name="name"></param>          /// <param name="interceptorTypes"></param>          /// <returns></returns>          public static IServiceCollection AddSbScoped(this IServiceCollection services, Type serviceType,              Type implementationType, string name = "", params Type[] interceptorTypes)          {              return services.AddSbService(serviceType, implementationType, ServiceLifetime.Scoped, name, interceptorTypes);          }            /// <summary>          /// 單例          /// </summary>          /// <typeparam name="TService"></typeparam>          /// <typeparam name="TImplementation"></typeparam>          /// <param name="services"></param>          /// <param name="name"></param>          /// <param name="interceptorTypes"></param>          /// <returns></returns>          public static IServiceCollection AddSbSingleton<TService, TImplementation>(this IServiceCollection services, string name = "", params Type[] interceptorTypes)          {              return services.AddSbService(typeof(TService), typeof(TImplementation), ServiceLifetime.Singleton, name, interceptorTypes);          }            /// <summary>          /// 單例          /// </summary>          /// <param name="services"></param>          /// <param name="serviceType"></param>          /// <param name="implementationType"></param>          /// <param name="name"></param>          /// <param name="interceptorTypes"></param>          /// <returns></returns>          public static IServiceCollection AddSbSingleton(this IServiceCollection services, Type serviceType,              Type implementationType, string name = "", params Type[] interceptorTypes)          {              return services.AddSbService(serviceType, implementationType, ServiceLifetime.Singleton, name, interceptorTypes);          }            public static IServiceCollection AddSbService(this IServiceCollection services, Type serviceType, Type implementationType,              ServiceLifetime lifetime, string name = "", params Type[] interceptorTypes)          {              services.Add(new ServiceDescriptor(implementationType, implementationType, lifetime));                object Factory(IServiceProvider provider)              {                  var target = provider.GetService(implementationType);                  var properties = implementationType.GetTypeInfo().DeclaredProperties;                    foreach (PropertyInfo info in properties)                  {                      //屬性注入                      if (info.GetCustomAttribute<AutowiredAttribute>() != null)                      {                          var propertyType = info.PropertyType;                          object impl = null;                          var qualifierAttribute = info.GetCustomAttribute<QualifierAttribute>();                          if (qualifierAttribute != null)                          {                              var serviceName = qualifierAttribute.Name;                              var implList = provider.GetServices(propertyType);                              foreach (var tmpImpl in implList)                              {                                  if (ProxyUtil.IsProxy(tmpImpl))                                  {                                      var addition = tmpImpl as IDependencyAddition;                                      if (addition?.Name == serviceName)                                      {                                          impl = tmpImpl;                                          break; ;                                      }                                  }                              }                          }                          else                          {                              impl = provider.GetService(propertyType);                          }                            if (impl != null)                          {                              info.SetValue(target, impl);                          }                      }                        //配置值注入                      if (info.GetCustomAttribute<ValueAttribute>() is ValueAttribute valueAttribute)                      {                          var value = valueAttribute.Value;                          if (provider.GetService(typeof(IConfiguration)) is IConfiguration configService)                          {                              var pathValue = configService.GetSection(value).Value;                              if (pathValue != null)                              {                                  var pathV = Convert.ChangeType(pathValue, info.PropertyType);                                  info.SetValue(target, pathV);                              }                          }                        }                  }                    List<IInterceptor> interceptors = interceptorTypes.ToList()                      .ConvertAll<IInterceptor>(interceptorType => provider.GetService(interceptorType) as IInterceptor);                    var proxyGenerator = provider.GetService<ProxyGenerator>();                  var options = new ProxyGenerationOptions();                  options.AddMixinInstance(new DependencyAddition() { Name = name });                  var proxy = proxyGenerator.CreateInterfaceProxyWithTarget(serviceType, target, options, interceptors.ToArray());                    return proxy;              };                var serviceDescriptor = new ServiceDescriptor(serviceType, Factory, lifetime);              services.Add(serviceDescriptor);                return services;          }      }
View Code

修改第一篇中自定義的控制器激活類SbControllerActivator,添加支援[QualifierAttribute]註解的邏輯。

 public class SbControllerActivator : IControllerActivator      {          /// <inheritdoc />          public object Create(ControllerContext actionContext)          {              if (actionContext == null)                  throw new ArgumentNullException(nameof(actionContext));                Type serviceType = actionContext.ActionDescriptor.ControllerTypeInfo.AsType();                var target = actionContext.HttpContext.RequestServices.GetRequiredService(serviceType);                var properties = serviceType.GetTypeInfo().DeclaredProperties;                var proxyGenerator = actionContext.HttpContext.RequestServices.GetService<ProxyGenerator>();                var proxy = proxyGenerator.CreateClassProxyWithTarget(serviceType, target);                foreach (PropertyInfo info in properties)              {                  //屬性注入                  if (info.GetCustomAttribute<AutowiredAttribute>() != null)                  {                      var propertyType = info.PropertyType;                      object impl = null;                      var qualifierAttribute = info.GetCustomAttribute<QualifierAttribute>();                      if (qualifierAttribute != null)                      {                          var serviceName = qualifierAttribute.Name;                          var implList = actionContext.HttpContext.RequestServices.GetServices(propertyType);                          foreach (var tmpImpl in implList)                          {                              if (ProxyUtil.IsProxy(tmpImpl))                              {                                  var addition = tmpImpl as IDependencyAddition;                                  if (addition?.Name == serviceName)                                  {                                      impl = tmpImpl;                                      break; ;                                  }                              }                          }                      }                      else                      {                          impl = actionContext.HttpContext.RequestServices.GetService(propertyType);                      }                        if (impl != null)                      {                          info.SetValue(proxy, impl);                      }                  }                    //配置值注入                  if (info.GetCustomAttribute<ValueAttribute>() is ValueAttribute valueAttribute)                  {                      var value = valueAttribute.Value;                      if (actionContext.HttpContext.RequestServices.GetService(typeof(IConfiguration)) is IConfiguration configService)                      {                          var pathValue = configService.GetSection(value).Value;                          if (pathValue != null)                          {                              var pathV = Convert.ChangeType(pathValue, info.PropertyType);                              info.SetValue(proxy, pathV);                          }                      }                    }              }                return proxy;          }            /// <inheritdoc />          public virtual void Release(ControllerContext context, object controller)          {          }      }
View Code

修改Startup.cs類里的ConfigureServices方法,可以看到,我們在註冊WheelA和WheelB的時候,為服務添加了名稱,並且隨手添加了個攔截器,程式碼如下:

 public void ConfigureServices(IServiceCollection services)          {              services.Configure<CookiePolicyOptions>(options =>              {                  // This lambda determines whether user consent for non-essential cookies is needed for a given request.                  options.CheckConsentNeeded = context => true;                  options.MinimumSameSitePolicy = SameSiteMode.None;              });                  services.AddMvc()                  .SetCompatibilityVersion(CompatibilityVersion.Version_2_1)                  .AddSB();                services.AddSingleton<ProxyGenerator>();                services.AddSbScoped<Engine>(typeof(TransactionalInterceptor));                services.AddSbScoped<IUnitOfWork, UnitOfWork>();              services.AddScoped(typeof(TransactionalInterceptor));                services.AddSbScoped<ICar, Car>(typeof(TransactionalInterceptor));                services.AddSbScoped<IDbFactory, DbFactory>();              services.AddSbRepositoryService(typeof(TransactionalInterceptor));              services.AddSbScoped<IAddOilService, AddOilService>(typeof(TransactionalInterceptor));                services.AddSbScoped<IWheel, WheelA>("A輪胎", typeof(TransactionalInterceptor));              services.AddSbScoped<IWheel, WheelB>("B輪胎", typeof(TransactionalInterceptor));          }

 控制器類HomeController,程式碼如下:

public class HomeController : Controller      {          [Autowired]          public ICar Car { set; get; }            [Autowired]          public IDistributedCache Cache { set; get; }            [Value("description")]          public string Description { set; get; }            [Autowired]          public IAddOilService AddOilService { set; get; }            public IActionResult Index()          {                var car = Car;                AddOilService.AddOil();                Car.Fire();                Console.WriteLine(Description);                return View();          }      }

核心原理,從SummerBootExtentions類完整源碼里單獨抽取mixin服務註冊和屬性注入的程式碼,可以看到在生成動態代理的時候,在option里添加了mixin實例,也就是我們自定義的DependencyAddition,裡面包含了這個服務的名稱,在注入時,判斷是否有[QualifierAttribute]註解,如果有,就獲取整個介面的實現類列表,在循環里,判斷是否為動態代理類,如果是,就把每個類實例強轉為附加類介面IDependencyAddition,然後獲取名稱,如果名稱和我們[QualifierAttribute]註解指定的名稱相同,則注入。

 var proxyGenerator = provider.GetService<ProxyGenerator>();                  var options = new ProxyGenerationOptions();                  options.AddMixinInstance(new DependencyAddition() { Name = name });                  var proxy = proxyGenerator.CreateInterfaceProxyWithTarget(serviceType, target, options, interceptors.ToArray());
//屬性注入                      if (info.GetCustomAttribute<AutowiredAttribute>() != null)                      {                          var propertyType = info.PropertyType;                          object impl = null;                          var qualifierAttribute = info.GetCustomAttribute<QualifierAttribute>();                          if (qualifierAttribute != null)                          {                              var serviceName = qualifierAttribute.Name;                              var implList = provider.GetServices(propertyType);                              foreach (var tmpImpl in implList)                              {                                  if (ProxyUtil.IsProxy(tmpImpl))                                  {                                      var addition = tmpImpl as IDependencyAddition;                                      if (addition?.Name == serviceName)                                      {                                          impl = tmpImpl;                                          break; ;                                      }                                  }                              }                          }                          else                          {                              impl = provider.GetService(propertyType);                          }                            if (impl != null)                          {                              info.SetValue(target, impl);                          }                      }

2.效果圖

先注入A輪胎

從上圖可以看到,生成的動態代理類里包含了Name這個屬性,並且名稱為A輪胎。

控制台輸出,也顯示了“我是A輪胎,我正在滾”,符合預期。

注入B輪胎

從上圖可以看到,生成的動態代理類里包含了Name這個屬性,並且名稱為B輪胎。

控制台輸出,也顯示了“我是B輪胎,我正在滾”,符合預期。

3. 寫在最後

        通過[Autowired]註解和[Qualifier("B輪胎")]註解聯合使用,我們就實現了一個介面多個實現類的精準屬性注入,程式碼看起來是不是舒服多了呢~,我始終相信,如果一件事我講的別人聽不明白,那一定是我講的不夠有趣,不夠通俗易懂,所以大白話是必須的,如果文章還有哪裡說得太深奧,歡迎給我指出來,同時net core里還有啥功能讓你覺得用起來特別彆扭的,請!一定!告訴我!,i will try it,因為這特別有趣,因為我一直踐行的編程理念就是萬物靠注入,萬物可攔截,萬物皆註解,始終相信IOC和AOP是構建軟體的基石,哈哈哈哈哈。

        如果這篇文章對你有所幫助,不妨點個贊咯。

Tags: