zoukankan      html  css  js  c++  java
  • Dora.Interception,为.NET Core度身打造的AOP框架 [4]:与依赖注入框架的无缝集成

      Dora.Interception最初的定位就是专门针对.NET Core的AOP框架,所以在整个迭代过程中我大部分是在做减法。对于.NET Core程序开发来说,依赖注入已经成为无处不在并且“深入骨髓”的东西,不论是在进行业务应用的开发,还是进行基础组件的开发,依赖注入是实现“松耦合”最为理想的方式(没有之一)。对于绝大部分AOP框架来说,它们最终都会体现为创建一个能够拦截的“代理对象”来实现对方法调用的拦截,但是.NET Core中针对服务实例的提供完全由通过IServiceProvider接口表示的DI容器来接管,所以Dora.Interception必须将两者无缝地集成在一起。与依赖注入框架的集成不仅仅体现在对可被拦截的代理对象的创建,同样应用在了针对拦截器的定义和注册上。

    一、IInterceptable<T>

    由于.NET Core总是采用IServiceProvider接口表示的DI容器来提供注入的依赖服务对象,现在我们得将原始的目标对象转换成能够被拦截代理对象,为此我们提供了一个泛型的服务接口IInterceptable<T>,它的Proxy属性返回的就是这么一个代理对象。

    public interface IInterceptable<T> where T: class
    {
        T Proxy { get; }
    }

    由于着了一个帮助我们提供可拦截代理的IInterceptable<T>服务,我们就可以在需要拦截目标类型的地方按照如下的方式注入该服务,并利用其Proxy属性得到这个可被拦截的代理。

    复制代码
    public class HomeController : Controller
    {
        private readonly ISystemClock _clock;
        public HomeController(IInterceptable<ISystemClock> clockAccessor)
        {
            _clock = clockAccessor.Proxy;
            Debug.Assert(typeof(SystemClock) != _clock.GetType());
        }
    }
    复制代码

    二、让IServiceProvider直接代理对象

    在被依赖类型的构造函数中注入IInterceptable<T>服务的编程方式总显得有点别扭,这要求所有具有AOP需求的组件都需要依赖Dora.Interception,这无疑是不现实的。我们最终需要解决的还是如何让IServiceProvider直接提供可被拦截的代理对象,为此我对.NET Core依赖注入框架的源代码作了一点很小的改动。这个经过简单修改的IServiceProvider实现类型就是如下这个InterceptableServiceProvider 类型。至于具体修改了什么,并不是一两句话就能说清楚的,这涉及到整个依赖注入框架的设计,有兴趣有查看源代码。

    复制代码
    internal sealed class InterceptableServiceProvider : IServiceProvider, IDisposable, IServiceProviderEngineCallback
    {
        internal InterceptableServiceProvider(IEnumerable<ServiceDescriptor> serviceDescriptors, ServiceProviderOptions options, IInterceptingProxyFactory interceptingProxyFactory);
        public void Dispose();
        public object GetService(Type serviceType);
        void IServiceProviderEngineCallback.OnCreate(IServiceCallSite callSite);
        void IServiceProviderEngineCallback.OnResolve(Type serviceType, IServiceScope scope);
    }
    复制代码

    我们在Startup类型的ConfigureServices方法中,调用IServiceCollection的扩展方法BuildInterceptableServiceProvider创建的就是这么一个InterceptableServiceProvider 对象。

    复制代码
    public class Startup
    {
        public IServiceProvider ConfigureServices(IServiceCollection services)
        {
            return services
                ...
                .BuildInterceptableServiceProvider();
        }
        ...
    }
    复制代码

    三、服务注册

    Dora.Interception所需的服务注册都是通过调用IServiceCollection的扩展方法AddInterception来完成的,由于AddInterception会调整现有的服务注册以支持上面介绍的IInterceptable<T>服务,所以AddInterception方法的调用需要放在所有服务注册结束之后。创建InterceptableServiceProvider的BuildInterceptableServiceProvider方法内部会调用AddInterception方法,但是不会对现有的服务注册作任何修改。

    复制代码
    public static class ServiceCollectionExtensions
    {
        public static IServiceCollection AddInterception(this IServiceCollection services, Action<InterceptionBuilder> configure = null);
        public static IServiceProvider BuildInterceptableServiceProvider(this IServiceCollection services, Action<InterceptionBuilder> configure = null);
        public static IServiceProvider BuildInterceptableServiceProvider(this IServiceCollection services, bool validateScopes, Action<InterceptionBuilder> configure = null);
    }
    复制代码

    AddInterception和BuildInterceptableServiceProvider方法均定义了一个Action<InterceptionBuilder>类型的参数,我们可以利用它对注册的服务做进一步定制。比如如果我们需要实现自定义的拦截器注册方式,只需要将自定义的IInterceptorProviderResolver对象添加到InterceptorProviderResolvers 属性表示的集合中即可。

    public class InterceptionBuilder
    {
        public InterceptionBuilder(IServiceCollection services);
        public InterceptorProviderResolverCollection InterceptorProviderResolvers { get; }
        public IServiceCollection Services { get; }
    }

    [1]:更加简练的编程体验
    [2]:基于约定的拦截器定义方式
    [3]:多样性的拦截器应用方式
    [4]:与依赖注入框架的深度整合
    [5]:对拦截机制的灵活定制

    作者:蒋金楠
    微信公众账号:大内老A
    微博:www.weibo.com/artech
    如果你想及时得到个人撰写文章以及著作的消息推送,或者想看看个人推荐的技术资料,可以扫描左边二维码(或者长按识别二维码)关注个人公众号)。
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
     
    ********转载:https://www.cnblogs.com/artech/p/dora-interception-04.html
  • 相关阅读:
    PAT (Advanced Level) 1086. Tree Traversals Again (25)
    PAT (Advanced Level) 1085. Perfect Sequence (25)
    PAT (Advanced Level) 1084. Broken Keyboard (20)
    PAT (Advanced Level) 1083. List Grades (25)
    PAT (Advanced Level) 1082. Read Number in Chinese (25)
    HDU 4513 吉哥系列故事――完美队形II
    POJ Oulipo KMP 模板题
    POJ 3376 Finding Palindromes
    扩展KMP
    HDU 2289 Cup
  • 原文地址:https://www.cnblogs.com/linybo/p/10053032.html
Copyright © 2011-2022 走看看