本来是没有打算写这篇分析的,但是在我分析缓存组件的时候,发现企业库的所有组件都是通过一种方式创建出来的,这就让我产生了好奇,于是决定去看看他到底是如何通过配置文件将正确的对象创建出来.
这里有四个重要的接口,一句话概括,就是配置器(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学习笔记