• 代码级浅析企业库对象创建


           本来是没有打算写这篇分析的,但是在我分析缓存组件的时候,发现企业库的所有组件都是通过一种方式创建出来的,这就让我产生了好奇,于是决定去看看他到底是如何通过配置文件将正确的对象创建出来.

     

          这里有四个重要的接口,一句话概括,就是配置器(IContainerConfigurator)以特定的解析方式(ITypeRegistrationsProvider)将源(IConfigurationSource)里的信息解析出来,最终发布为服务定位器(IServiceLocator).

          一.服务定位器

     

          可以从图上看到,其实所谓的企业库服务定位器,其实就是对依赖注入框架Unity的一个封装,通过GetInstance<T>方法来解析接口及其实现类的匹配.

          二.配置器

     

          配置器是一个完成类型注册的过程.从图上可以看到,Unity容器内的注册信息是通过UnityContainerConfigurator来进行注册的.进行注册的代码为:

    container.RegisterType(registrationEntry.ServiceType, registrationEntry.ImplementationType, registrationEntry.Name, CreateLifetimeManager(registrationEntry), GetInjectionMembers(registrationEntry));

          其本质是向Unity容器进行类型注册.注册完成之后,就可以通过UnityServiceLocator向外提供服务了.

          三.配置源


          我们的配置信息一般写在系统的配置文件中,而IconfigurationSource接口则负责从文件中读取相关信息.从上图可以看到,真正的实现类是SystemConfigurationSource类. 在其里面有这样一句代码:

    return AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;

          这也决定了系统只能从默认的配置文件中读取信息.

          四.解析方式

     

          可以从图中看到,所以解析,就是把配置文件分析成一个接口与实现类的映射表.TypeRegistrationProvidersConfigurationSection,TypeRegistrationProviderElementCollection与TypeRegistrationProviderElement,分别对应配置文件里的配置节,配置元素集合与配置元素,BlockSectionNames类则定义了企业库使用的配置节名称.重点看ConfigurationBasedTypeRegistrationsProviderFactory类的CreateTypeRegistrationsProviderLocators方法,代码如下:

     1 TypeRegistrationProvidersConfigurationSection section = configurationSource.GetSection(TypeRegistrationProvidersConfigurationSection.SectionName) as TypeRegistrationProvidersConfigurationSection;
     2 if (section == null)
     3 {
     4     section = new TypeRegistrationProvidersConfigurationSection();
     5 }
     6 
     7 foreach (TypeRegistrationProviderElement typeRegistrationProviderElement in section.TypeRegistrationProviders)
     8 {
     9     if (!string.IsNullOrEmpty(typeRegistrationProviderElement.SectionName) &&
    10         !string.IsNullOrEmpty(typeRegistrationProviderElement.ProviderTypeName))
    11     {
    12         throw new ConfigurationErrorsException(
    13             string.Format("Type Registration Provider Settings '{0}' cannot declare both sectionName and providerType attributes",
    14             typeRegistrationProviderElement.Name));
    15     }
    16     if (!string.IsNullOrEmpty(typeRegistrationProviderElement.SectionName))
    17     {
    18         yield return new ConfigSectionLocator(typeRegistrationProviderElement.SectionName, reconfiguringEventSource);
    19     }
    20     else if (!string.IsNullOrEmpty(typeRegistrationProviderElement.ProviderTypeName))
    21     {
    22         yield return new TypeLoadingLocator(typeRegistrationProviderElement.ProviderTypeName, reconfiguringEventSource);
    23     }
    24 }

          第四行新建了一个TypeRegistrationProvidersConfigurationSection对象,其TypeRegistrationProviders属性在返回时,会创建库业库默认使用的节点集合,代码如下:

    public TypeRegistrationProviderElementCollection()
    {
        BaseAdd(new TypeRegistrationProviderElement() { Name = TypeRegistrationProvidersConfigurationSection.CachingTypeRegistrationProviderName, SectionName = BlockSectionNames.Caching });
        BaseAdd(new TypeRegistrationProviderElement() { Name = TypeRegistrationProvidersConfigurationSection.CryptographyTypeRegistrationProviderName, SectionName = BlockSectionNames.Cryptography });
        BaseAdd(new TypeRegistrationProviderElement() { Name = TypeRegistrationProvidersConfigurationSection.ExceptionHandlingTypeRegistrationProviderName, SectionName = BlockSectionNames.ExceptionHandling });
        BaseAdd(new TypeRegistrationProviderElement() { Name = TypeRegistrationProvidersConfigurationSection.InstrumentationTypeRegistrationProviderName, SectionName = BlockSectionNames.Instrumentation });
        BaseAdd(new TypeRegistrationProviderElement() { Name = TypeRegistrationProvidersConfigurationSection.LoggingTypeRegistrationProviderName, SectionName = BlockSectionNames.Logging });
        BaseAdd(new TypeRegistrationProviderElement() { Name = TypeRegistrationProvidersConfigurationSection.PolicyInjectionTypeRegistrationProviderName, SectionName = BlockSectionNames.PolicyInjection });
        BaseAdd(new TypeRegistrationProviderElement() { Name = TypeRegistrationProvidersConfigurationSection.SecurityTypeRegistrationProviderName, SectionName = BlockSectionNames.Security });
        BaseAdd(new TypeRegistrationProviderElement() { Name = TypeRegistrationProvidersConfigurationSection.DataAccessTypeRegistrationProviderName, ProviderTypeName = BlockSectionNames.DataRegistrationProviderLocatorType });
        BaseAdd(new TypeRegistrationProviderElement() { Name = TypeRegistrationProvidersConfigurationSection.ValidationTypeRegistrationProviderName,  ProviderTypeName = BlockSectionNames.ValidationRegistrationProviderLocatorType });
    }

          下面就是读取这些节点的信息了, 代码第18行与第22行就是跟据不同的情况创建不同的定位器.

          到目前为止, 只是知道了企业库会使用哪些配置节,那具体的分析工作呢,还是回到UnityContainerConfigurator类吧:

     1 protected override void RegisterAllCore(IConfigurationSource configurationSource, ITypeRegistrationsProvider rootProvider)
     2 {
     3     EnterWriteLock();
     4     try
     5     {
     6         foreach (var registration in rootProvider.GetRegistrations(configurationSource))
     7         {
     8             Register(registration);
     9         }
    10     }
    11     finally
    12     {
    13         ExitWriteLock();
    14     }
    15 }

          可以看到由ITypeRegistrationsProvider接口完成.而TypeRegistrationsProvider抽象类实现了这个接口,TypeLoadingLocator与ConfigSectionLocator又继承了这个抽象类.随便看一个吧:

    public override IEnumerable<TypeRegistration> GetRegistrations(IConfigurationSource configurationSource)
    {
        return GetRegistrationsInternal(configurationSource, (p, cs) => p.GetRegistrations(cs));
    }

     

     1 private IEnumerable<TypeRegistration> GetRegistrationsInternal(IConfigurationSource configurationSource,
     2     Func<ITypeRegistrationsProvider, IConfigurationSource, IEnumerable<TypeRegistration>> registrationsAccessor)
     3 {
     4     ITypeRegistrationsProvider provider = null;
     5     ConfigurationSection section = configurationSource.GetSection(Name);
     6     if (section != null)
     7     {
     8         provider = section as ITypeRegistrationsProvider;
     9     }
    10 
    11     if (provider != null)
    12     {
    13         return registrationsAccessor(provider, configurationSource);
    14     }
    15     return Enumerable.Empty<TypeRegistration>();
    16 }

          其首先从源中获取指定节点,然后把其强转成ITypeRegistrationsProvider再调用其GetRegistrations方法获取真正的配置信息.比如缓存配置,用GetSection获取后其实就是CacheManagerSettings类,其实现了ITypeRegistrationsProvider接口,调用其GetRegistrations方法解析缓存配置.


          是不是感觉很乱?反正我是这么认为的.搞不懂不就是解析一个配置文件嘛,干嘛要搞这么复杂,难道不多转几个弯就不能体现企业库的NB与价值?!个人感觉最乱的就是对于ITypeRegistrationsProvider接口的使用.UnityContainerConfigurator类调用ITypeRegistrationsProvider接口,实际是调用CompositeTypeRegistrationsProviderLocator类.这个类的内部维护了一个ITypeRegistrationsProvider接口集合,其GetRegistrations方法就是遍例这个集合逐个调用各自GetRegistrations方法.实际上这个集合装着的是TypeLoadingLocator类与ConfigSectionLocator类,那么调用的就是这两个类的方法.然后这两个类又把源获取一遍,把获取的结果转成ITypeRegistrationsProvider接口,然后再调转换后的GetRegistrations方法.到了这一步,才真正把该拿的信息拿出来!有必要搞的这么复杂吗?!

          参考的文章:

          微软企业库5.0学习笔记

  • 相关阅读:
    alloffthelights使用方法
    tweenMax学习笔记
    移动端获取手机摄像头和相册
    livereload使用方法
    Bower使用笔记
    github 远程仓库
    git for windows 本地仓库
    python 对文件操作
    Python 装饰器
    JavaScript 做的网页版扫雷小游戏
  • 原文地址:https://www.cnblogs.com/ljzforever/p/2291909.html
Copyright © 2020-2023  润新知