net core天马行空系列: 一个接口多个实现类,利用mixin技术通过自定义服务名,实现精准属性注入

系列目录

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;
        }
    }

修改第一篇中自定义的控制器激活类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)
        {
        }
    }

修改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是构建软件的基石,哈哈哈哈哈。

如果这篇文章对你有所帮助,不妨点个赞咯。

原文地址:https://www.cnblogs.com/hezp/p/11495147.html

时间: 2024-10-13 19:07:45

net core天马行空系列: 一个接口多个实现类,利用mixin技术通过自定义服务名,实现精准属性注入的相关文章

net core天马行空系列:SummerBoot,将SpringBoot的先进理念与C#的简洁优雅合二为一

系列目录 1.net core天马行空系列:原生DI+AOP实现spring boot注解式编程 2.net core天马行空系列: 泛型仓储和声明式事物实现最优雅的crud操作 3.net core天马行空系列: 一个接口多个实现类,利用mixin技术通过自定义服务名,实现精准属性注入 4.net core天马行空系列:移植spring cache,实现支持条件限定,事务环绕,多级复用的注解式缓存(除了多级复用以外,代码已完成,博客正在写) 5.net core天马行空系列:利用AOP,在da

.NET Core中的一个接口多种实现的依赖注入与动态选择看这篇就够了

最近有个需求就是一个抽象仓储层接口方法需要SqlServer以及Oracle两种实现方式,为了灵活我在依赖注入的时候把这两种实现都给注入进了依赖注入容器中,但是在服务调用的时候总是获取到最后注入的那个方法的实现,这时候就在想能不能实现动态的选择使用哪种实现呢?如果可以的话那么我只需要在配置文件中进行相应的配置即可获取到正确的实现方法的调用,这样的话岂不快哉!今天我们就来一起探讨下实现这种需求的几种实现方式吧. 作者:依乐祝 原文地址:https://www.cnblogs.com/yilezhu

@resource、@Autowired、@Service在一个接口多个实现类中的应用

Spring在没有引入注解之前,传统的Spring做法是使用.xml文件来对bean进行注入,所有的内容都需要配置在.xml文件中,使配置和编程分离,却增加了可读性和复杂度. Spring注解将复杂的配置文件用简单@xxx代替,当出现一个接口多个实现类的时候,究竟是用的哪个实现类呢? 示例代码: public interface DataDao{} @Service public class ImgDataDao implements DataDao{ } @Service public cla

对象导论系列---每个对象都至少有一个接口

对象导论系列---每个对象都至少有一个接口 面向对象程序设计主要是用来解决人们实际生产.生活中遇到的问题.通过将现实生活中的问题和解空间中的对象进行映射,并对对象进行抽象.关联.组合.发送消息来具体解决实际问题.现实生活中的实体也都是有自己的特性和行为的,并且每个实体都会与其范围内的其它实体有关系,有的是强关系,有的是弱关系. 下面看下本节的关键性概念(思想) 类:将具有相同特性和行为的一类实体定义为类.当看到类型一词时,可以将其作为类来考虑.因为类描述了具有相同特性(数据元素)和行为(功能)的

.net core实践系列之SSO-跨域实现

前言 接着上篇的<.net core实践系列之SSO-同域实现>,这次来聊聊SSO跨域的实现方式.这次虽说是.net core实践,但是核心点使用jquery居多. 建议看这篇文章的朋友可以先看上篇<.net core实践系列之SSO-同域实现>做一个SSO大概了解. 源码地址:https://github.com/SkyChenSky/Core.SSO.git 效果图 知识点回顾 实现原则 只要统一Token的产生和校验方式,无论授权与认证的在哪(认证系统或业务系统),也无论用户

射频识别技术漫谈(20)——RC系列射频接口芯片

目前基于13.56MHz的射频识别技术主要有ISO14443A.ISO14443B.ISO15693和FELICA技术.针对13.56MHz的射频识别技术,NXP开发了一系列名字以RC(Radio Chip)开头的射频接口芯片,包括RC500.RC400.RC530.RC531.RC632等,这些芯片的设计架构.引脚排列.内部寄存器阵列.天线设计等方面基本相同,不同之处主要是与微控制器的接口界面.支持的协议种类等不一样.后来的RC522.PN512也大体继承了同样的设计思路,只是在供电电压和封装

[转]C#进阶系列——WebApi 接口返回值不困惑:返回值类型详解

本文转自:http://www.cnblogs.com/landeanfen/p/5501487.html 阅读目录 一.void无返回值 二.IHttpActionResult 1.Json(T content) 2.Ok(). Ok(T content) 3.NotFound() 4.其他 5.自定义IHttpActionResult接口的实现 三.HttpResponseMessage 四.自定义类型 五.总结 正文 前言:已经有一个月没写点什么了,感觉心里空落落的.今天再来篇干货,想要学

[implements] - 一个接口的使用

4种货物,如何使用一个接口实现CRUD: package com.tansuo365.test1.service.goods; import com.tansuo365.test1.entity.Goods; import com.tansuo365.test1.mapper.goods.IGoodsCommonMapper; import java.util.List; /** * 货品公用service接口 * {@link #setGoodsTypeMapper 设置货品类型} * {@l

.Net Core 跨平台:一个简单程序的多平台(windows、Linux、osx)发布

.Net Core 跨平台:一个简单程序的多平台(windows.Linux.osx)发布 .Net Core 3.0 已于2019年9月23日发布了,包含了一些新特性,具体参见Announcing .NET Core 3.0 .NET Core是一个跨平台,高性能,开放源代码框架,用于构建现代的,基于云的,Internet连接的应用程序框架,其具有一下优点和特点: 跨平台:.NET Framework应用程序仅在Windows平台上运行,而.NET Core应用程序可以在Windows平台上开