微软企业库源码解析——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的工作原理也就明晰了。

原文地址:https://www.cnblogs.com/HCOONa/p/1524402.html