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

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

 

 

      这里有四个重要的接口,一句话概括,就是配置器(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学习笔记

 

posted @ 2011-12-18 18:31  永远的阿哲  阅读(444)  评论(0编辑  收藏  举报