• 微软企业库源码解析——DAAB(三)DatabaseFactory(其余的Strategy)


    下面我们继续分析剩下的三个Strategy:

       1: stagedStrategyChain.AddNew<LocatorLookupStrategy>(BuilderStage.PreCreation);
       2: stagedStrategyChain.AddNew<ConfiguredObjectStrategy>(BuilderStage.PreCreation);
       3: stagedStrategyChain.AddNew<InstrumentationStrategy>(BuilderStage.PostInitialization);

    先看LocatorLookupStrategy

       1: public override void PreBuildUp(IBuilderContext context)
       2: {
       3:     if (context.Locator != null)
       4:     {
       5:         Monitor.Enter(context.Locator);
       6:         context.RecoveryStack.Add(new LockReleaser(context.Locator));
       7:         object result = context.Locator.Get(context.BuildKey);
       8:         if (result != null)
       9:         {
      10:             context.Existing = result;
      11:             context.BuildComplete = true;
      12:             Monitor.Exit(context.Locator);
      13:         }
      14:     }
      15: }

    还记得我们在BuildUp中Locator是null,所以这个Strategy在这里没起任何作用

    下面我们来看ConfiguredObjectStrategy,这个策略是整个装配过程的重点

       1: /// <summary>
       2: /// Implementation of <see cref="IBuilderStrategy"/> which creates objects.
       3: /// </summary>
       4: /// <remarks>
       5: /// <para>The strategy looks for the <see cref="CustomFactoryAttribute">CustomFactory</see> attribute to 
       6: /// retrieve the <see cref="ICustomFactory"/> implementation needed to build the requested types based on 
       7: /// configuration.</para>
       8: /// <para>The provided context must have a <see cref="ConfigurationObjectPolicy"/> holding a <see cref="IConfigurationSource"/>
       9: /// where to request the configuration information.</para>
      10: /// </remarks>
      11: /// <seealso cref="ICustomFactory"/>
      12: /// <seealso cref="CustomFactoryAttribute"/>
      13: /// <seealso cref="ConfigurationObjectPolicy"/>
      14: public class ConfiguredObjectStrategy : EnterpriseLibraryBuilderStrategy
      15: {
      16:     /// <summary>
      17:     /// Override of <see cref="IBuilderStrategy.PreBuildUp"/>. 
      18:     /// Creates the requested object using the custom factory associated to the type specified by the context's key,
      19:     /// and updates the context's existing object.
      20:     /// </summary>
      21:     /// <param name="context">The <see cref="IBuilderContext"/> that represents the current building process.</param>
      22:     /// <exception cref="InvalidOperationException"> when the requested type does not have the 
      23:     /// required <see cref="CustomFactoryAttribute">CustomFactory</see> attribute.</exception>
      24:     /// <exception cref="System.Configuration.ConfigurationErrorsException"> when the configuration for the requested ID is not present or is 
      25:     /// invalid in the configuration source.</exception>
      26:     public override void PreBuildUp(IBuilderContext context)
      27:     {
      28:         base.PreBuildUp(context);
      29:  
      30:         IConfigurationSource configurationSource = GetConfigurationSource(context);
      31:         ConfigurationReflectionCache reflectionCache = GetReflectionCache(context);
      32:  
      33:         NamedTypeBuildKey key = (NamedTypeBuildKey) context.BuildKey;
      34:         string id = key.Name;
      35:         Type t = key.Type;
      36:  
      37:         ICustomFactory factory = GetCustomFactory(t, reflectionCache);
      38:         if (factory != null)
      39:         {
      40:             context.Existing = factory.CreateObject(context, id, configurationSource, reflectionCache);
      41:         }
      42:         else
      43:         {
      44:             throw new InvalidOperationException(
      45:                 string.Format(
      46:                     Resources.Culture,
      47:                     Resources.ExceptionCustomFactoryAttributeNotFound,
      48:                     t.FullName,
      49:                     id));
      50:         }
      51:     }
      52:  
      53:     private static ICustomFactory GetCustomFactory(Type t, ConfigurationReflectionCache reflectionCache)
      54:     {
      55:         ICustomFactory customFactory = reflectionCache.GetCustomFactory(t);
      56:  
      57:         return customFactory;
      58:     }
      59: }

    GetCustomFactory这句得到的是Database类中的Attribute标记的

    [CustomFactory(typeof(DatabaseCustomFactory))]

    string id是前一篇文章得到的DefaultDatabase或者是指定的数据连接字符串的Name

    具体的追踪过程请参见该系列文章的第二篇

    接下来我们来看DatabaseCustomFactory

       1: /// <summary>
       2: /// This type supports the Enterprise Library infrastructure and is not intended to be used directly from your code.
       3: /// Represents the process to build a <see cref="Database"/> described by configuration information.
       4: /// </summary>
       5: public class DatabaseCustomFactory : ICustomFactory
       6: {
       7:     private IDictionary<Type, IDatabaseAssembler> assemblersMapping = new Dictionary<Type, IDatabaseAssembler>(5);
       8:     private object assemblersMappingLock = new object();
       9:  
      10:     /// <summary>
      11:     /// This method supports the Enterprise Library infrastructure and is not intended to be used directly from your code.
      12:     /// Returns an <see cref="IDatabaseAssembler"/> that represents the building process for a a concrete <see cref="Database"/>.
      13:     /// </summary>
      14:     /// <param name="type">The concrete <see cref="Database"/> type.</param>
      15:     /// <param name="name">The name of the instance to build, or <see langword="null"/> (<b>Nothing</b> in Visual Basic).</param>
      16:     /// <param name="reflectionCache">The cache to use retrieving reflection information.</param>
      17:     /// <returns>The <see cref="IDatabaseAssembler"/> instance.</returns>
      18:     /// <exception cref="InvalidOperationException">when concrete <see cref="Database"/> type does have the required <see cref="DatabaseAssemblerAttribute"/>.</exception>
      19:     public IDatabaseAssembler GetAssembler(Type type, string name, ConfigurationReflectionCache reflectionCache)
      20:     {
      21:         bool exists = false;
      22:         IDatabaseAssembler assembler;
      23:         lock (assemblersMappingLock)
      24:         {
      25:             exists = assemblersMapping.TryGetValue(type, out assembler);
      26:         }
      27:         if (!exists)
      28:         {
      29:             DatabaseAssemblerAttribute assemblerAttribute
      30:                 = reflectionCache.GetCustomAttribute<DatabaseAssemblerAttribute>(type);
      31:             if (assemblerAttribute == null)
      32:                 throw new InvalidOperationException(
      33:                     string.Format(
      34:                         Resources.Culture,
      35:                         Resources.ExceptionDatabaseTypeDoesNotHaveAssemblerAttribute,
      36:                         type.FullName,
      37:                         name));
      38:  
      39:             assembler
      40:                 = (IDatabaseAssembler)Activator.CreateInstance(assemblerAttribute.AssemblerType);
      41:  
      42:             lock (assemblersMappingLock)
      43:             {
      44:                 assemblersMapping[type] = assembler;
      45:             }
      46:         }
      47:         
      48:         return assembler;
      49:     }
      50:  
      51:     /// <summary>
      52:     /// This method supports the Enterprise Library infrastructure and is not intended to be used directly from your code.
      53:     /// Returns a new instance of a concrete <see cref="Database"/>, described by the <see cref="ConnectionStringSettings"/> 
      54:     /// found in the <paramref name="configurationSource"/> under the name <paramref name="name"/>, plus any additional
      55:     /// configuration information that might describe the the concrete <b>Database</b>.
      56:     /// </summary>
      57:     /// <param name="context">The <see cref="IBuilderContext"/> that represents the current building process.</param>
      58:     /// <param name="name">The name of the instance to build, or <see langword="null"/> (<b>Nothing</b> in Visual Basic).</param>
      59:     /// <param name="configurationSource">The source for configuration objects.</param>
      60:     /// <param name="reflectionCache">The cache to use retrieving reflection information.</param>
      61:     /// <returns>A new instance of the appropriate subtype of <typeparamref name="Tobject"/>.</returns>
      62:     /// <exception cref="ConfigurationErrorsException">when the configuration is invalid or <paramref name="name"/> cannot be found.</exception>
      63:     public object CreateObject(IBuilderContext context, string name, IConfigurationSource configurationSource, ConfigurationReflectionCache reflectionCache)
      64:     {
      65:         DatabaseConfigurationView configurationView = new DatabaseConfigurationView(configurationSource);
      66:         ConnectionStringSettings connectionStringSettings = configurationView.GetConnectionStringSettings(name);
      67:         DbProviderMapping mapping = configurationView.GetProviderMapping(name, connectionStringSettings.ProviderName);
      68:  
      69:         IDatabaseAssembler assembler = GetAssembler(mapping.DatabaseType, name, reflectionCache);
      70:         Database database = assembler.Assemble(name, connectionStringSettings, configurationSource);
      71:  
      72:         return database;
      73:     }
      74: }

    DatabaseConfigurationView就是把xxx.config当做只跟数据获取块有关的配置文件看待,这一点跟DataView有异曲同工之妙。

    下面来看ConnectionStringSettings是怎么得到的。

       1: /// <summary>
       2: /// Returns the <see cref="ConnectionStringSettings"/> object with the given name from the connection strings
       3: /// configuration section in the receiver's configuration source.
       4: /// </summary>
       5: /// <remarks>
       6: /// The connection string will be retrieved from the configuration source if it contains the connection strings section,
       7: /// otherwise it will be retrieved from the default configuration file.
       8: /// </remarks>
       9: /// <param name="name">The name for the desired connection string configuration.</param>
      10: /// <returns>The connection string configuration.</returns>
      11: /// <exception cref="ArgumentException">if <paramref name="name"/> is <see langword="null"/> (<b>Nothing</b> in Visual Basic) or empty.</exception>
      12: /// <exception cref="ConfigurationErrorsException">if the connection string object is not found, or if it does not specify a provider name.</exception>
      13: public ConnectionStringSettings GetConnectionStringSettings(string name)
      14: {
      15:     ValidateInstanceName(name);
      16:  
      17:     ConnectionStringSettings connectionStringSettings;
      18:     ConfigurationSection configSection = configurationSource.GetSection("connectionStrings");
      19:     if ((configSection != null) && (configSection is ConnectionStringsSection))
      20:     {
      21:         ConnectionStringsSection connectionStringsSection = configSection as ConnectionStringsSection;
      22:         connectionStringSettings = connectionStringsSection.ConnectionStrings[name];
      23:     }
      24:     else
      25:         connectionStringSettings = ConfigurationManager.ConnectionStrings[name];
      26:  
      27:     ValidateConnectionStringSettings(name, connectionStringSettings);
      28:     return connectionStringSettings;
      29: }

    这里首先检索的是ConfigurationSource中是否含有connectionStrings配置节,如果不含有的话,再从默认的配置源(web.config或者app.config)中获取包含指定name的连接字符串

    接下来我们看DbProviderMapping是怎么得到的

       1: /// <summary>
       2: /// Returns the <see cref="DbProviderMapping"/> that specifies the mapping between an ADO.NET provider factory and a
       3: /// <see cref="Database"/> instance.
       4: /// </summary>
       5: /// <remarks>
       6: /// The mapping based in logical names will be probed first. If there is no success, the default type based mappings
       7: /// will be considered. If no default mapping is defined for the provider factory type, the generic database will be used.
       8: /// </remarks>
       9: /// <param name="name">The name of the <see cref="Database"/> instance.</param>
      10: /// <param name="dbProviderName">The logical provider name.</param>
      11: /// <returns>The <see cref="DbProviderMapping"/> that matches the <paramref name="dbProviderName"/>.</returns>
      12: public DbProviderMapping GetProviderMapping(string name, string dbProviderName)
      13: {
      14:     DatabaseSettings settings = this.DatabaseSettings;
      15:     if (settings != null)
      16:     {
      17:         DbProviderMapping existingMapping = settings.ProviderMappings.Get(dbProviderName);
      18:         if (existingMapping != null)
      19:         {
      20:             return existingMapping;
      21:         }
      22:     }
      23:  
      24:     DbProviderMapping defaultMapping = this.GetDefaultMapping(name, dbProviderName);
      25:     if (defaultMapping != null)
      26:     {
      27:         return defaultMapping;
      28:     }
      29:  
      30:     return this.GetGenericMapping();
      31: }

    说实在的,这段代码我很不理解,不理解的地方在于这句

    DbProviderMapping existingMapping = settings.ProviderMappings.Get(dbProviderName);

    Settings的获得是从配置文件中的dataConfiguration配置节中读取的

    然而ProviderMappings具有Attribute标记

    [ConfigurationProperty(dbProviderMappingsProperty, IsRequired = false)]

    其中dbProviderMappingsProperty=”providerMappings”

    然而,无论我怎么在配置文件中找,也没有找到providerMappings这个配置节或者是属性

    这样的话

    [ConfigurationProperty(dbProviderMappingsProperty, IsRequired = false)]
    public NamedElementCollection<DbProviderMapping> ProviderMappings
    {
    get
    {
    return (NamedElementCollection<DbProviderMapping>)base[dbProviderMappingsProperty];
    }
    }

    应该返回的是null?不知道ConfigurationManager.GetSection是怎么处理的,反正在MSDN上我是没有找到什么有用的资料,不知道有没有哪位不吝赐教。

    如果那里返回的是null的话,这句话就该有空引用的异常

    DbProviderMapping existingMapping = settings.ProviderMappings.Get(dbProviderName);

    如果不是null的话,又是如何实例化的NamedElementCollection<DbProviderMapping>呢

    在此留下一个疑问,留待后人解决。

    这里,我们可以猜测到,DbProviderMapping是用来根据配置文件中的ProviderName来确定的,从而根据这个mapping来获得相应的SqlDatabase或者是其他的Database。

    IDatabaseAssembler assembler = GetAssembler(mapping.DatabaseType, name, reflectionCache);

    mapping.DatabaseType就是SqlDatabase或者OracleDatabase或者GenericDatabase,具体是哪个由配置文件决定。

    /// <summary>
    /// This method supports the Enterprise Library infrastructure and is not intended to be used directly from your code.
    /// Returns an <see cref="IDatabaseAssembler"/> that represents the building process for a a concrete <see cref="Database"/>.
    /// </summary>
    /// <param name="type">The concrete <see cref="Database"/> type.</param>
    /// <param name="name">The name of the instance to build, or <see langword="null"/> (<b>Nothing</b> in Visual Basic).</param>
    /// <param name="reflectionCache">The cache to use retrieving reflection information.</param>
    /// <returns>The <see cref="IDatabaseAssembler"/> instance.</returns>
    /// <exception cref="InvalidOperationException">when concrete <see cref="Database"/> type does have the required <see cref="DatabaseAssemblerAttribute"/>.</exception>
    public IDatabaseAssembler GetAssembler(Type type, string name, ConfigurationReflectionCache reflectionCache)
    {
    bool exists = false;
    IDatabaseAssembler assembler;
    lock (assemblersMappingLock)
    {
    exists = assemblersMapping.TryGetValue(type, out assembler);
    }
    if (!exists)
    {
    DatabaseAssemblerAttribute assemblerAttribute
    = reflectionCache.GetCustomAttribute<DatabaseAssemblerAttribute>(type);
    if (assemblerAttribute == null)
    throw new InvalidOperationException(
    string.Format(
    Resources.Culture,
    Resources.ExceptionDatabaseTypeDoesNotHaveAssemblerAttribute,
    type.FullName,
    name));

    assembler
    = (IDatabaseAssembler)Activator.CreateInstance(assemblerAttribute.AssemblerType);

    lock (assemblersMappingLock)
    {
    assemblersMapping[type] = assembler;
    }
    }

    return assembler;
    }

    这里通过反射得到了相应Database的程序集,比如说SqlDatabaseAssembler

    然后通过该Assembler的Assemble方法得到了相应的Database

    到这里,就已经完成了相应Database的创建。

    下面是InstrumentationStrategy

       1: public override void PreBuildUp(IBuilderContext context)
       2: {
       3:     base.PreBuildUp(context);
       4:  
       5:     if (context.Existing != null && context.Existing is IInstrumentationEventProvider)
       6:     {
       7:         IConfigurationSource configurationSource = GetConfigurationSource(context);
       8:         ConfigurationReflectionCache reflectionCache = GetReflectionCache(context);
       9:  
      10:         NamedTypeBuildKey key = (NamedTypeBuildKey)context.BuildKey;
      11:         string id = key.Name;
      12:  
      13:         InstrumentationAttachmentStrategy instrumentation = new InstrumentationAttachmentStrategy();
      14:  
      15:         if (ConfigurationNameProvider.IsMadeUpName(id))
      16:         {
      17:             instrumentation.AttachInstrumentation(context.Existing, configurationSource, reflectionCache);
      18:         }
      19:         else
      20:         {
      21:             instrumentation.AttachInstrumentation(id, context.Existing, configurationSource, reflectionCache);
      22:         }
      23:     }
      24: }

    检查了所有的Database,发现其父类Database实现了IInstrumentationEventProvider接口。

    我们来看ConfigurationNameProvider的IsMadeUpName方法

       1: /// <summary>
       2: /// Manages the creation of names for anonymous instances.
       3: /// </summary>
       4: public static class ConfigurationNameProvider
       5: {
       6:     private const string nameSuffix = "___";
       7:  
       8:     /// <summary>
       9:     /// Creates a new name.
      10:     /// </summary>
      11:     /// <returns>The created name.</returns>
      12:     public static string MakeUpName()
      13:     {
      14:         return Guid.NewGuid().ToString() + nameSuffix;
      15:     }
      16:  
      17:     /// <summary>
      18:     /// Tests a name to determine if it has been created.
      19:     /// </summary>
      20:     /// <param name="name">The name to test.</param>
      21:     /// <returns><b>true</b> if the name was made up.</returns>
      22:     public static bool IsMadeUpName(string name)
      23:     {
      24:         if (name == null) return false;
      25:         
      26:         return name.EndsWith(nameSuffix);
      27:     }    
      28: }

    根据注释,ConfigurationNameProvider就是专门用来管理BuildKey.Name的类。这个类的MakeUpName方法在前面的分析中没有被调用过,而且BuildKey.Name也不是以"___"结尾,所以应该进入方法:

    instrumentation.AttachInstrumentation(id, context.Existing, configurationSource, reflectionCache);

    /// <summary>
    /// Drives binding of instrumentation events to handler methods based on the attributes on the
    /// source object.
    /// </summary>
    public class InstrumentationAttachmentStrategy
    {
    InstrumentationAttacherFactory attacherFactory = new InstrumentationAttacherFactory();

    /// <overloads>
    /// Attaches the instrumentation events in the <paramref name="createdObject"></paramref> to the
    /// creating instance of the listener object, as defined by the <see cref="InstrumentationListenerAttribute"></see>
    /// on the source class.
    /// </overloads>
    /// <summary>
    /// Attaches the instrumentation events in the <paramref name="createdObject"></paramref> to the
    /// creating instance of the listener object, as defined by the <see cref="InstrumentationListenerAttribute"></see>
    /// on the source class.
    /// </summary>
    /// <param name="createdObject">Source object used for instrumentation events.</param>
    /// <param name="configurationSource"><see cref="IConfigurationSource"></see> instance used to define whether
    /// instrumentation is enabled or disabled for application.</param>
    /// <param name="reflectionCache">Cache for instrumentation attributes discovered through reflection.</param>
    public void AttachInstrumentation(object createdObject, IConfigurationSource configurationSource, ConfigurationReflectionCache reflectionCache)
    {
    ArgumentGenerator arguments = new ArgumentGenerator();
    AttachInstrumentation(arguments, createdObject, configurationSource, reflectionCache);
    }

    /// <summary>
    /// Attaches the instrumentation events in the <paramref name="createdObject"></paramref> to the
    /// creating instance of the listener object, as defined by the <see cref="InstrumentationListenerAttribute"></see>
    /// on the source class.
    /// </summary>
    /// <param name="instanceName">User-provided instance name given to the instrumenation listener during its instantiation.</param>
    /// <param name="createdObject">Source object used for instrumentation events.</param>
    /// <param name="configurationSource"><see cref="IConfigurationSource"></see> instance used to define whether
    /// instrumentation is enabled or disabled for application.</param>
    /// <param name="reflectionCache">Cache for instrumentation attributes discovered through reflection.</param>
    public void AttachInstrumentation(string instanceName, object createdObject, IConfigurationSource configurationSource, ConfigurationReflectionCache reflectionCache)
    {
    ArgumentGenerator arguments = new ArgumentGenerator(instanceName);
    AttachInstrumentation(arguments, createdObject, configurationSource, reflectionCache);
    }

    private void AttachInstrumentation(ArgumentGenerator arguments, object createdObject,
    IConfigurationSource configurationSource,
    ConfigurationReflectionCache reflectionCache)
    {
    InstrumentationConfigurationSection section = GetConfigurationSection(configurationSource);
    if (section.InstrumentationIsEntirelyDisabled) return;

    if (createdObject is IInstrumentationEventProvider)
    {
    createdObject = ((IInstrumentationEventProvider)createdObject).GetInstrumentationEventProvider();
    }

    object[] constructorArgs = arguments.ToArguments(section);

    BindInstrumentationTo(createdObject, constructorArgs, reflectionCache);
    }

    private void BindInstrumentationTo(object createdObject, object[] constructorArgs, ConfigurationReflectionCache reflectionCache)
    {
    IInstrumentationAttacher attacher = attacherFactory.CreateBinder(createdObject, constructorArgs, reflectionCache);
    attacher.BindInstrumentation();
    }

    private InstrumentationConfigurationSection GetConfigurationSection(IConfigurationSource configurationSource)
    {
    InstrumentationConfigurationSection section =
    (InstrumentationConfigurationSection)configurationSource.GetSection(InstrumentationConfigurationSection.SectionName);
    if (section == null) section = new InstrumentationConfigurationSection(false, false, false);

    return section;
    }

    private class ArgumentGenerator
    {
    private string instanceName;

    public ArgumentGenerator(string instanceName)
    {
    this.instanceName = instanceName;
    }

    public ArgumentGenerator() { }

    public object[] ToArguments(InstrumentationConfigurationSection configSection)
    {
    return instanceName == null
    ?
    new object[] { configSection.PerformanceCountersEnabled, configSection.EventLoggingEnabled, configSection.WmiEnabled, configSection.ApplicationInstanceName }
    :
    new object[]
    {
    instanceName, configSection.PerformanceCountersEnabled, configSection.EventLoggingEnabled,
    configSection.WmiEnabled, configSection.ApplicationInstanceName
    };
    }
    }
    }

    首先,AttachInstrumentation方法构造了一个用来传递参数的类ArgumentGenerator。然后通过configurationSource获得了InstrumentationConfigurationSection配置节,如果该配置节不存在,就创建一个PerformanceCountersEnabled,EventLoggingEnabled,WmiEnabled都为False的InstrumentationConfigurationSection实例。

    紧接着,在这句,如果没有配置过InstrumentationConfigurationSection的话

    if (section.InstrumentationIsEntirelyDisabled) return;

    就返回了,因为

    internal bool InstrumentationIsEntirelyDisabled
    {
    get { return (PerformanceCountersEnabled || EventLoggingEnabled || WmiEnabled) == false; }
    }

    而刚刚直接新建了一个这三个值都是False的InstrumentationConfigurationSection实例。

    如果配置过InstrumentationConfigurationSection的话,createObject是某个Database的实例,他们都继承自Database类,Database类实现了接口IInstrumentationEventProvider,该方法返回了类DataInstrumentationProvider。现在createObject指向了Database返回的类DataInstrumentationProvider。接下来,刚刚构造的用来生成参数的类ArgumentGenerator生成了一系列参数。

    接下来我们来看那个attacher。

    IInstrumentationAttacher attacher = attacherFactory.CreateBinder(createdObject, constructorArgs, reflectionCache);

    首先得看attacherFactory。attacherFactory是在类InstrumentationAttachmentStrategy一开始就声明并赋值的一个变量。

    InstrumentationAttacherFactory attacherFactory = new InstrumentationAttacherFactory();

    我们来看InstrumentationAttacherFactory的CreateBinder方法

       1: /// <summary>
       2: /// Represents a factor to attach instrumentation objects.
       3: /// </summary>
       4: public class InstrumentationAttacherFactory
       5: {
       6:     /// <summary>
       7:     /// Create the binder for instrumentation.
       8:     /// </summary>
       9:     /// <param name="createdObject">The created object for the attacher.</param>
      10:     /// <param name="constructorArgs">The construcor objects.</param>
      11:     /// <param name="reflectionCache">The relection cache.</param>
      12:     /// <returns>An <see cref="IInstrumentationAttacher"/> object.</returns>
      13:     public IInstrumentationAttacher CreateBinder(object createdObject,
      14:                                                  object[] constructorArgs,
      15:                                                  ConfigurationReflectionCache reflectionCache)
      16:     {
      17:         InstrumentationListenerAttribute listenerAttribute = GetInstrumentationListenerAttribute(createdObject, reflectionCache);
      18:  
      19:         if (listenerAttribute == null) return new NoBindingInstrumentationAttacher();
      20:  
      21:         Type listenerType = listenerAttribute.ListenerType;
      22:         Type listenerBinderType = listenerAttribute.ListenerBinderType;
      23:  
      24:         if (listenerBinderType == null) return new ReflectionInstrumentationAttacher(createdObject, listenerType, constructorArgs);
      25:         return new ExplicitInstrumentationAttacher(createdObject, listenerType, constructorArgs, listenerBinderType);
      26:     }
      27:  
      28:     static InstrumentationListenerAttribute GetInstrumentationListenerAttribute(object createdObject,
      29:                                                                          ConfigurationReflectionCache reflectionCache)
      30:     {
      31:         Type createdObjectType = createdObject.GetType();
      32:         InstrumentationListenerAttribute listenerAttribute
      33:             = reflectionCache.GetCustomAttribute<InstrumentationListenerAttribute>(createdObjectType, true);
      34:         return listenerAttribute;
      35:     }
      36: }

    首先,用ConfigurationReflectionCache反射得到了createObject的InstrumentationListenerAttribute,也就是DataInstrumentationProvider的InstrumentationListenerAttribute:

    [InstrumentationListener(typeof(DataInstrumentationListener), typeof(DataInstrumentationListenerBinder))]
    public class DataInstrumentationProvider

    然后返回了一个ExplicitInstrumentationAttacher,我们来看ExplicitInstrumentationAttacher的BindInstrumentation方法

       1: public void BindInstrumentation()
       2: {
       3:     IExplicitInstrumentationBinder binder = (IExplicitInstrumentationBinder) Activator.CreateInstance(explicitBinderType);
       4:     object listener = Activator.CreateInstance(listenerType, listenerConstructorArguments);
       5:     
       6:     binder.Bind(source, listener);
       7: }

    先创建了刚刚得到的InstrumentationListenerAttribute中的DataInstrumentationListenerBinder。然后用刚刚的参数生成类ArgumentGenerator生成的参数创建了DataInstrumentationListener。然后调用Binder的Bind方法将DataInstrumentationListener和DataInstrumentationProvider绑定到一起。

    这样一来,每当出现指定的操作的时候,就可以根据配置文件中的配置来决定是否进行性能计数,事件日志等操作。具体来说,就是将DataInstrumentationProvider中的事件

       1: /// <summary>
       2: /// Occurs when a new database connection is opened by a <see cref="Database"/> instance.
       3: /// </summary>
       4: [InstrumentationProvider("ConnectionOpened")]
       5: public event EventHandler<EventArgs> connectionOpened;
       6:  
       7: /// <summary>
       8: /// Occurs when the attempt to open a new database connection by a <see cref="Database"/> instance fails.
       9: /// </summary>
      10: [InstrumentationProvider("ConnectionFailed")]
      11: public event EventHandler<ConnectionFailedEventArgs> connectionFailed;
      12:  
      13: /// <summary>
      14: /// Occurs when a database command is executed by a <see cref="Database"/> instance.
      15: /// </summary>
      16: [InstrumentationProvider("CommandExecuted")]
      17: public event EventHandler<CommandExecutedEventArgs> commandExecuted;
      18:  
      19: /// <summary>
      20: /// Occurs when the attempt to execute a database command by a <see cref="Database"/> instance fails.
      21: /// </summary>
      22: [InstrumentationProvider("CommandFailed")]
      23: public event EventHandler<CommandFailedEventArgs> commandFailed;

    绑定到具体处理这些事件的类DataInstrumentationListener上

       1: public void Bind(object source, object listener)
       2: {
       3:     DataInstrumentationListener castedListener = (DataInstrumentationListener)listener;
       4:     DataInstrumentationProvider castedProvider = (DataInstrumentationProvider)source;
       5:  
       6:     castedProvider.commandExecuted += castedListener.CommandExecuted;
       7:     castedProvider.commandFailed += castedListener.CommandFailed;
       8:     castedProvider.connectionFailed += castedListener.ConnectionFailed;
       9:     castedProvider.connectionOpened += castedListener.ConnectionOpened;
      10: }

    至此,所有的Strategy都分析完毕。

    DatabaseFactory的工作原理也就明晰了。

  • 相关阅读:
    中介者模式
    Redis安装
    观察者模式
    第三天:创建型模式--建造者模式
    第二天:创建型模式--抽象工厂模式
    第一天:创建型模式--工厂方法模式
    17天17个Python设计模式--目录
    Python模拟登陆新版知乎
    Flask架站基础篇(八)--SQLAlchemy(2)
    Flask架站基础篇(七)--SQLAlchemy(1)
  • 原文地址:https://www.cnblogs.com/HCOONa/p/1524402.html
Copyright © 2020-2023  润新知