微软企业库源码解析——DAAB(二)DatabaseFact

系统 2067 0

其实跟踪到这里我就已经崩溃了,不过为了让问题水落石出,我们祭出Reflactor继续追踪下去。

        
             1:
        
        
          public
        
         TTypeToBuild BuildUp<TTypeToBuild>(IReadWriteLocator locator, ILifetimeContainer lifetime, IPolicyList policies, IStrategyChain strategies, 
        
          object
        
         buildKey, 
        
          object
        
         existing)
      
        
             2:
        
         {
      
        
             3:
        
        
          return
        
         (TTypeToBuild) 
        
          this
        
        .BuildUp(locator, lifetime, policies, strategies, buildKey, existing);
      
        
             4:
        
         }
      
        
             5:
        
          
      
        
             6:
        
        
          public
        
        
          object
        
         BuildUp(IReadWriteLocator locator, ILifetimeContainer lifetime, IPolicyList policies, IStrategyChain strategies, 
        
          object
        
         buildKey, 
        
          object
        
         existing)
      
        
             7:
        
         {
      
        
             8:
        
             Guard.ArgumentNotNull(strategies, 
        
          "strategies"
        
        );
      
        
             9:
        
             BuilderContext context = 
        
          new
        
         BuilderContext(strategies, locator, lifetime, policies, buildKey, existing);
      
        
            10:
        
        
          return
        
         strategies.ExecuteBuildUp(context);
      
        
            11:
        
         }
      

这里面的Guard是用来检测各种参数的,其中提供了类似于ArgumentNotNull之类的一系列方法,也是比较常用的,将参数检测集中起来的方法,值得大家学习。

可以看到,Builder用了StrategyChain进行的装配。所以,我们又得返回去看看StrategyChain里面都有什么东西。

找到EnterpriseLibraryFactory的构造函数,发现StrategyChain是这么出来的

        
             1:
        
         StagedStrategyChain<BuilderStage> stagedStrategyChain = 
        
          new
        
         StagedStrategyChain<BuilderStage>();
      
        
             2:
        
         stagedStrategyChain.AddNew<ConfigurationNameMappingStrategy>(BuilderStage.PreCreation);
      
        
             3:
        
         stagedStrategyChain.AddNew<LocatorLookupStrategy>(BuilderStage.PreCreation);
      
        
             4:
        
         stagedStrategyChain.AddNew<ConfiguredObjectStrategy>(BuilderStage.PreCreation);
      
        
             5:
        
         stagedStrategyChain.AddNew<InstrumentationStrategy>(BuilderStage.PostInitialization);
      
        
             6:
        
         strategyChain = stagedStrategyChain.MakeStrategyChain();
      

据我猜测,BuilderStage应该是说明在何时这个策略参与对象的装配的。

我们从第一个Strategy开始看,即ConfigurationNameMappingStrategy。

        
             1:
        
        
          /// <summary>
        
      
        
             2:
        
        
          /// Implementation of <see cref="IBuilderStrategy"/> which maps null instance names into a different name.
        
      
        
             3:
        
        
          /// </summary>
        
      
        
             4:
        
        
          /// <remarks>
        
      
        
             5:
        
        
          /// The strategy is used to deal with default names.
        
      
        
             6:
        
        
          /// </remarks>
        
      
        
             7:
        
        
          /// <seealso cref="ConfigurationNameMapperAttribute"/>
        
      
        
             8:
        
        
          /// <seealso cref="IConfigurationNameMapper"/>
        
      
        
             9:
        
        
          public
        
        
          class
        
         ConfigurationNameMappingStrategy : EnterpriseLibraryBuilderStrategy
      
        
            10:
        
         {
      
        
            11:
        
        
          /// <summary>
        
      
        
            12:
        
        
          /// Override of <see cref="IBuilderStrategy.PreBuildUp"/>. Updates the instance name using a name mapper associated to type 
        
      
        
            13:
        
        
          /// to build so later strategies in the build chain will use the updated instance name.
        
      
        
            14:
        
        
          /// </summary>
        
      
        
            15:
        
        
          /// <remarks>
        
      
        
            16:
        
        
          /// Will only update the instance name if it is <see langword="null"/>.
        
      
        
            17:
        
        
          /// </remarks>
        
      
        
            18:
        
        
          /// <param name="context">The <see cref="IBuilderContext"/> that represents the current building process.</param>
        
      
        
            19:
        
        
          /// <exception cref="System.Configuration.ConfigurationErrorsException"> when the configuration required to do the mapping is not present or is 
        
      
        
            20:
        
        
          /// invalid in the configuration source.</exception>
        
      
        
            21:
        
        
          public
        
        
          override
        
        
          void
        
         PreBuildUp(IBuilderContext context)
      
        
            22:
        
             {
      
        
            23:
        
        
          base
        
        .PreBuildUp(context);
      
        
            24:
        
          
      
        
            25:
        
                 NamedTypeBuildKey key = (NamedTypeBuildKey) context.BuildKey;
      
        
            26:
        
          
      
        
            27:
        
        
          if
        
         (key.Name == 
        
          null
        
        )
      
        
            28:
        
                 {
      
        
            29:
        
                     ConfigurationReflectionCache reflectionCache = GetReflectionCache(context);
      
        
            30:
        
          
      
        
            31:
        
                     IConfigurationNameMapper mapper = reflectionCache.GetConfigurationNameMapper(key.Type);
      
        
            32:
        
        
          if
        
         (mapper != 
        
          null
        
        )
      
        
            33:
        
                     {
      
        
            34:
        
                         context.BuildKey = 
        
          new
        
         NamedTypeBuildKey(key.Type, mapper.MapName(
        
          null
        
        , GetConfigurationSource(context)));
      
        
            35:
        
                     }
      
        
            36:
        
                 }
      
        
            37:
        
             }
      
        
            38:
        
         }
      

从注释我们可以看出,这个策略是为了将默认名称取出来并替换null名称的。刚刚我们CreateDatabase的时候如果不加上实例名的话,传递的就是null。这个策略就是将这个null的实例名替换成被标记为Default的实例名,以便下面的装配工作顺利进行。

我们看到PreBuildUp方法是override的,同时还调用了base.PreBuildUp。在ConfigurationNameMappingStrategy的父类EnterpriseLibraryBuilderStrategy中没有覆盖PreBuildUp方法。我用Reflactor查看了EnterpriseLibraryBuilderStrategy的父类BuilderStrategy,看到了BuilderStrategy的四个方法

        
             1:
        
        
          public
        
        
          virtual
        
        
          void
        
         PostBuildUp(IBuilderContext context);
      
        
             2:
        
        
          public
        
        
          virtual
        
        
          void
        
         PostTearDown(IBuilderContext context);
      
        
             3:
        
        
          public
        
        
          virtual
        
        
          void
        
         PreBuildUp(IBuilderContext context);
      
        
             4:
        
        
          public
        
        
          virtual
        
        
          void
        
         PreTearDown(IBuilderContext context);
      

都是空方法

NamedTypeBuildKey key实际上就是在EnterpriseLibraryFactory中调用BuildUp时传递的参数NamedTypeBuildKey.Make<T>(),而这个方法得到的是NamedTypeBuildKey(typeof(T))。

GetReflectionCache方法是在其父类EnterpriseLibraryBuilderStrategy中定义的

        
             1:
        
        
          protected
        
        
          static
        
         ConfigurationReflectionCache GetReflectionCache(IBuilderContext context)
      
        
             2:
        
         {
      
        
             3:
        
             IReflectionCachePolicy policy
      
        
             4:
        
                 = context.Policies.Get<IReflectionCachePolicy>(
        
          typeof
        
        (IReflectionCachePolicy));
      
        
             5:
        
          
      
        
             6:
        
        
          if
        
         (policy == 
        
          null
        
        )
      
        
             7:
        
        
          return
        
        
          new
        
         ConfigurationReflectionCache();
      
        
             8:
        
        
          else
        
      
        
             9:
        
        
          return
        
         policy.ReflectionCache;
      
        
            10:
        
         }
      

reflectionCache.GetConfigurationNameMapper(key.Type)这里经过了一系列复杂的变化后得到了Database标记中包含的Attribute中指定的ConfigurationNameMapper:DatabaseMapper。这里,我们不用太担心反射的性能,因为微软企业库对反射后的结果等都进行了缓存,大大提高了效率,所以,我们完全可以在需要时随时创建Database实例。

再来看mapper.MapName

        
             1:
        
        
          /// <summary>
        
      
        
             2:
        
        
          /// This method supports the Enterprise Library infrastructure and is not intended to be used directly from your code.
        
      
        
             3:
        
        
          /// Returns the default database name from the configuration in the <paramref name="configSource"/>, if the
        
      
        
             4:
        
        
          /// value for <paramref name="name"/> is <see langword="null"/> (<b>Nothing</b> in Visual Basic).
        
      
        
             5:
        
        
          /// </summary>
        
      
        
             6:
        
        
          /// <param name="name">The current name.</param>
        
      
        
             7:
        
        
          /// <param name="configSource">The source for configuration information.</param>
        
      
        
             8:
        
        
          /// <returns>The default database name if <paramref name="name"/> is <see langword="null"/> (<b>Nothing</b> in Visual Basic),
        
      
        
             9:
        
        
          /// otherwise the original value for <b>name</b>.</returns>
        
      
        
            10:
        
        
          public
        
        
          string
        
         MapName(
        
          string
        
         name, IConfigurationSource configSource)
      
        
            11:
        
         {
      
        
            12:
        
        
          if
        
         (name != 
        
          null
        
        )
      
        
            13:
        
        
          return
        
         name;
      
        
            14:
        
          
      
        
            15:
        
        
          return
        
        
          new
        
         DatabaseConfigurationView(configSource).DefaultName;
      
        
            16:
        
         }
      

继续跟踪到DatabaseConfigurationView

        
             1:
        
        
          /// <summary>
        
      
        
             2:
        
        
          /// <para>Gets the <see cref="DatabaseSettings"/> configuration data.</para>
        
      
        
             3:
        
        
          /// </summary>
        
      
        
             4:
        
        
          /// <returns>
        
      
        
             5:
        
        
          /// <para>The <see cref="DatabaseSettings"/> configuration data.</para>
        
      
        
             6:
        
        
          /// </returns>
        
      
        
             7:
        
        
          public
        
         DatabaseSettings DatabaseSettings
      
        
             8:
        
         {
      
        
             9:
        
             get { 
        
          return
        
         (DatabaseSettings)configurationSource.GetSection(DatabaseSettings.SectionName); }
      
        
            10:
        
         }
      
        
            11:
        
          
      
        
            12:
        
        
          /// <summary>
        
      
        
            13:
        
        
          /// <para>Gets the name of the default configured <see cref="Database"/>.</para>
        
      
        
            14:
        
        
          /// </summary>
        
      
        
            15:
        
        
          /// <returns>
        
      
        
            16:
        
        
          /// <para>The name of the default configured <see cref="Database"/>.</para>
        
      
        
            17:
        
        
          /// </returns>
        
      
        
            18:
        
        
          public
        
        
          string
        
         DefaultName
      
        
            19:
        
         {
      
        
            20:
        
             get
      
        
            21:
        
             {
      
        
            22:
        
                 DatabaseSettings settings = 
        
          this
        
        .DatabaseSettings;
      
        
            23:
        
        
          string
        
         databaseName = settings != 
        
          null
        
         ? settings.DefaultDatabase : 
        
          null
        
        ;
      
        
            24:
        
        
          return
        
         databaseName;
      
        
            25:
        
             }
      
        
            26:
        
         }
      

这里的configurationSource就是一开始在DatabaseFactory中ConfigurationSourceFactory.Create()得到的,后来经过各种传递用在这里了。

接下来我们只好跑到ConfigurationSourceFactory中看看是怎么回事了。

        
             1:
        
        
          /// <summary>
        
      
        
             2:
        
        
          /// Creates a new configuration sources based on the default configuration information from the 
        
      
        
             3:
        
        
          /// application's default configuration file.
        
      
        
             4:
        
        
          /// </summary>
        
      
        
             5:
        
        
          /// <returns>The new configuration source instance described as the default in the configuration file,
        
      
        
             6:
        
        
          /// or a new instance of <see cref="SystemConfigurationSource"/> if the is no configuration sources configuration.</returns>
        
      
        
             7:
        
        
          /// <exception cref="ConfigurationSourceSection">when there is a configuration section but it does not define
        
      
        
             8:
        
        
          /// a default configurtion source, or when the configuration for the defined default configuration source is not found.</exception>
        
      
        
             9:
        
        
          public
        
        
          static
        
         IConfigurationSource Create()
      
        
            10:
        
         {
      
        
            11:
        
             ConfigurationSourceSection configurationSourceSection
      
        
            12:
        
                 = ConfigurationSourceSection.GetConfigurationSourceSection();
      
        
            13:
        
          
      
        
            14:
        
        
          if
        
         (configurationSourceSection != 
        
          null
        
        )
      
        
            15:
        
             {
      
        
            16:
        
        
          string
        
         systemSourceName = configurationSourceSection.SelectedSource;
      
        
            17:
        
        
          if
        
         (!
        
          string
        
        .IsNullOrEmpty(systemSourceName))
      
        
            18:
        
                 {
      
        
            19:
        
        
          return
        
         Create(systemSourceName);
      
        
            20:
        
                 }
      
        
            21:
        
        
          else
        
      
        
            22:
        
                 {
      
        
            23:
        
        
          throw
        
        
          new
        
         ConfigurationErrorsException(Resources.ExceptionSystemSourceNotDefined);
      
        
            24:
        
                 }
      
        
            25:
        
             }
      
        
            26:
        
          
      
        
            27:
        
        
          return
        
        
          new
        
         SystemConfigurationSource();
      
        
            28:
        
         }
      

接下来先得看看这句

      ConfigurationSourceSection configurationSourceSection = ConfigurationSourceSection.GetConfigurationSourceSection();
    

这句得到的configurationSourceSection如果是null的话,就直接返回了SystemConfigurationSource

      
        /// <summary>
      
      
/// Configuration section for the configuration sources.
/// </summary>
/// <remarks>
/// This configuration must reside in the application's default configuration file.
/// </remarks>
public class ConfigurationSourceSection : SerializableConfigurationSection
{
private const string selectedSourceProperty = "selectedSource" ;
private const string sourcesProperty = "sources" ;

/// <summary>
/// This field supports the Enterprise Library infrastructure and is not intended to be used directly from your code.
/// </summary>
public const string SectionName = "enterpriseLibrary.ConfigurationSource" ;

/// <summary>
/// Returns the <see cref="ConfigurationSourceSection"/> from the application's default configuration file.
/// </summary>
/// <returns>The section from the configuration file, or <see langword="null"/> (<b>Nothing</b> in Visual Basic) if the section is not present in the configuration file.</returns>
public static ConfigurationSourceSection GetConfigurationSourceSection()
{
return (ConfigurationSourceSection)ConfigurationManager.GetSection(SectionName);
}

/// <summary>
/// Gets or sets the name for the default configuration source.
/// </summary>
[ConfigurationProperty(selectedSourceProperty, IsRequired= true )]
public string SelectedSource
{
get
{
return ( string ) this [selectedSourceProperty];
}
set
{
this [selectedSourceProperty] = value ;
}
}

/// <summary>
/// Gets the collection of defined configuration sources.
/// </summary>
[ConfigurationProperty(sourcesProperty, IsRequired = true )]
public NameTypeConfigurationElementCollection<ConfigurationSourceElement, ConfigurationSourceElement> Sources
{
get
{
return (NameTypeConfigurationElementCollection<ConfigurationSourceElement, ConfigurationSourceElement>) this [sourcesProperty];
}

}
}

可以看出,这里实际上是从App.config或者Web.config中读取节enterpriseLibrary.ConfigurationSource

这是Entlib4里面新加入的功能,可以把配置节独立出来存储到别的文件中,没有尝试过的朋友可以打开微软企业库4.1试一试

image

这样的话,也就是说,如果选择了ConfigurationSource的话就从该位置读取配置,否则就从SystemConfigurationSource读取配置

之后自然是顺理成章的从dataConfiguration配置节中读取DefaultDatabase,并且替换context中的BuildKey中的null值。

EntLib的庞大实在是令我崩溃,只好把这个策略再划分出来了。

不过不得不佩服ObjectBuilder的设计者,太强大了。

微软企业库源码解析——DAAB(二)DatabaseFactory(ConfigurationNameMappingStrategy篇)


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论