ObjectBuilder技术内幕(四)

ObjectBuilder技术内幕之四

随着故事线索的发展,我们慢慢接近了OB的核心场景,这个场景的主角就是一个个安插在责任链上的BuiderStrategy家族成员以及和与它们相关的BuilderPolicy。在阅读代码的时候,这两组类需要相互参照,为了便于理解,我们先看看OB的缺省情况下的对象创建过程,这可以从Builder类的一个参数构造器开始,我们把Builder类的详细介绍放到最后,这样更容易理解。

 

public Builder(IBuilderConfigurator<BuilderStage> configurator)

{

       Strategies.AddNew<TypeMappingStrategy>(BuilderStage.PreCreation);

       Strategies.AddNew<SingletonStrategy>(BuilderStage.PreCreation);

       Strategies.AddNew<ConstructorReflectionStrategy>(BuilderStage.PreCreation);

       Strategies.AddNew<PropertyReflectionStrategy>(BuilderStage.PreCreation);

       Strategies.AddNew<MethodReflectionStrategy>(BuilderStage.PreCreation);

       Strategies.AddNew<CreationStrategy>(BuilderStage.Creation);

       Strategies.AddNew<PropertySetterStrategy>(BuilderStage.Initialization);

       Strategies.AddNew<MethodExecutionStrategy>(BuilderStage.Initialization);

       Strategies.AddNew<BuilderAwareStrategy>(BuilderStage.PostInitialization);

 

       Policies.SetDefault<ICreationPolicy>(new DefaultCreationPolicy());

 

       if (configurator != null)

              configurator.ApplyConfiguration(this);

}

 

上面的代码中,我们看到Builder在策略表中都安排了哪些策略,下面是这些策略的次序和所在的阶段:

预创建阶段:

TypeMappingStrategy : 类型映射策略

SingletonStrategy: 单例策略

ConstructorReflectionStrategy: 构造器反射策略

PropertyReflectionStrategy: 属性反射策略

MothodReflectionStrategy: 方法反射策略

创建阶段

CreationStrategy: 创建策略

初始化阶段

PropertySetterStrategy: 属性设置器策略

MothodExecutionStrategy: 方法执行策略

初始化完成阶段

BuilderAwareStrategy: 创建器感知策略

类型映射策略和方针

类型映射策略的目的就是通过查看创建器上下文中方针表,查询是否存在将一个基类映射到一个具体类的方针:

 

public class TypeMappingStrategy : BuilderStrategy

{

       public override object BuildUp(IBuilderContext context, Type t, object existing, string id)

       {

              DependencyResolutionLocatorKey result = new DependencyResolutionLocatorKey(t, id);

              ITypeMappingPolicy policy = context.Policies.Get<ITypeMappingPolicy>(t, id);

 

              if (policy != null)

              {

                     result = policy.Map(result);

                     TraceBuildUp(context, t, id, Properties.Resources.TypeMapped, result.Type, result.ID ?? "(null)");

                     Guard.TypeIsAssignableFromType(t, result.Type, t);

              }

 

              return base.BuildUp(context, result.Type, existing, result.ID);

       }

}

 

BuildUp方法被调用的时候(方法中t参数是要被创建对象的类型,existing是已经存在的对象实例,id参数是要创建对象的字符串标识),首先使用类型和字符串标识创建一个DependencyResolutionLocatorKey对象(通常是作为定位器中的对象的标识键),DependencyResolutionLocatorKey的定义如下:

 

public sealed class DependencyResolutionLocatorKey

{

       private Type type;

       private string id;

 

       public DependencyResolutionLocatorKey()

              : this(null, null)

       {

       }

 

       public DependencyResolutionLocatorKey(Type type, string id)

       {

              this.type = type;

              this.id = id;

       }

 

       public string ID

       {

              get { return id; }

       }

 

       public Type Type

       {

              get { return type; }

       }

 

       public override bool Equals(object obj)

       {

              DependencyResolutionLocatorKey other = obj as DependencyResolutionLocatorKey;

 

              if (other == null)

                     return false;

 

              return (Equals(type, other.type) && Equals(id, other.id));

       }

 

       public override int GetHashCode()

       {

              int hashForType = type == null ? 0 : type.GetHashCode();

              int hashForID = id == null ? 0 : id.GetHashCode();

              return hashForType ^ hashForID;

       }

}

 

这个类规定了两个对象如果它们类型和字符串标识一致,就认为是同一个对象。

接下来,查询创建器上下文的方针表中是否存在实现了ITypeMappingPolicy接口的类型映射方针,如果存在的话,就将刚才创建的DependencyResolutionLocatorKey对象作为参数调用方针的Map方法,然后从方法中返回的对象中检查两者的类型时候存在继承或者匹配关系(通过Guard.TypeIsAssignableFromType(t, result.Type, t)语句),如果不存在这样的关系,那么将抛出一个异常,创建终止。TypeIsAssignableFromType方法在Guard类中定义:

 

public static void TypeIsAssignableFromType(Type assignee, Type providedType, Type classBeingBuilt)

{

       if (!assignee.IsAssignableFrom(providedType))

              throw new IncompatibleTypesException(string.Format(CultureInfo.CurrentCulture,

                                   Properties.Resources.TypeNotCompatible, assignee, providedType, classBeingBuilt));

}

 

代码是自解释的(这种会说话的代码阅读起来很舒服)。

在测试类型关系之前,如果存在跟踪方针的话,这个Builder过程就会被记录。BuildUp最后的代码把映射后的类型作为要创建的对象类型作为参数,将创建工作移交给下一个策略(通过调用基类的BuildUp方法)。

现在我们来看看OB中缺省的类型映射方针:

 

public class TypeMappingPolicy : ITypeMappingPolicy

{

       private DependencyResolutionLocatorKey pair;

 

       public TypeMappingPolicy(Type type, string id)

       {

              pair = new DependencyResolutionLocatorKey(type, id);

       }

 

       public DependencyResolutionLocatorKey Map(DependencyResolutionLocatorKey incomingTypeIDPair)

       {

              return pair;

       }

}

 

方针中保存了一个DependencyResolutionLocatorKey的实例,Map方法简单的返回这个实例对象,而不管方法的参数是什么。由于策略中查询的是接口,所以如果你有自己的映射方针,只要编写你自己的Map方法然后让你的类实现ITypeMappingPolicy接口(还记得吗?这个接口是一个不包含任何方法的空接口)。

单例策略

如果你熟悉单例设计模式,你对Singleton这个词一定不会陌生。单例表示一个对象的实例在程序中只有一个,也就是说它们只被创建一次。但是这里的单例策略所指的单例概念不同,单例策略在这里的作用是充当短路器,它查看当前的定位器中是否已经存在要创建的对象,如果有,它就把对象返回,否则它把控制权移交给下一个策略。单例策略本身并不负责创建对象。如果给出要创建同一个类型但是对象字符串标识不同的话,单例策略看待它们是两个不同的对象。单例策略并不使用单例方针,单例方针将在对象创建的时候被使用。单例方针的代码非常简单,只是表示要创建的对象是否是单例对象(代码略)。

反射创建策略

实施反射策略的一个主要目的就是支持对象创建时的依赖注入。OB的反射策略有:
ConstructorReflectionStrategy

PropertyReflectionStrategy

MethodReflectionStrategy

三个类从ReflectionStrategy基类派生。

 

public abstract class ReflectionStrategy<TMemberInfo> : BuilderStrategy

{

    //查找类型中实施了依赖注入特性的成员(属性或者构造器的参数)

       protected abstract IEnumerable<IReflectionMemberInfo<TMemberInfo>> GetMembers(IBuilderContext context, Type typeToBuild, object existing, string idToBuild);

 

       //对每一个找到的成员,如果需要处理的话,就生成相应的信息(参数类型、参数值等),并保存到上下文的对应的方针中,以便在创建阶段得到正确的创建

       public override object BuildUp(IBuilderContext context, Type typeToBuild, object existing, string idToBuild)

       {

              foreach (IReflectionMemberInfo<TMemberInfo> member in GetMembers(context, typeToBuild, existing, idToBuild))

              {

                     if (MemberRequiresProcessing(member))

                     {

                            IEnumerable<IParameter> parameters = GenerateIParametersFromParameterInfos(member.GetParameters());

                            AddParametersToPolicy(context, typeToBuild, idToBuild, member, parameters);

                     }

              }

 

              return base.BuildUp(context, typeToBuild, existing, idToBuild);

       }

 

    //用于派生类实现增加参数信息到方针中的方法。

       protected abstract void AddParametersToPolicy(IBuilderContext context, Type typeToBuild, string idToBuild,

                     IReflectionMemberInfo<TMemberInfo> member, IEnumerable<IParameter> parameters);

 

       //从参数信息中生成参数

       private IEnumerable<IParameter> GenerateIParametersFromParameterInfos(ParameterInfo[] parameterInfos)

       {

              List<IParameter> result = new List<IParameter>();

 

              foreach (ParameterInfo parameterInfo in parameterInfos)

              {

                     ParameterAttribute attribute = GetInjectionAttribute(parameterInfo);

                     result.Add(attribute.CreateParameter(parameterInfo.ParameterType));

              }

 

              return result;

       }

 

       //获取参数特性的方法

       private ParameterAttribute GetInjectionAttribute(ParameterInfo parameterInfo)

       {

              ParameterAttribute[] attributes = (ParameterAttribute[])parameterInfo.GetCustomAttributes(typeof(ParameterAttribute), true);

 

              switch (attributes.Length)

              {

                     case 0:

                            return new DependencyAttribute();

 

                     case 1:

                            return attributes[0];

 

                     default:

                            throw new InvalidAttributeException();

              }

       }

 

       //派生类决定一个成员是否需要处理

       protected abstract bool MemberRequiresProcessing(IReflectionMemberInfo<TMemberInfo> member);

}

 

GetMembers需要派生类返回的是IReflectionMemberInfo类型的枚举集合,IReflectionMemberInfo如下定义:

 

public interface IReflectionMemberInfo<TMemberInfo>

{

       //原成员信息对象

       TMemberInfo MemberInfo { get; }

 

       //成员名称

       string Name { get; }

 

       //成员的自定义特性

       object[] GetCustomAttributes(Type attributeType, bool inherit);

 

       //传递给成员的参数

       ParameterInfo[] GetParameters();

}

 

具体类的实现代码:

 

public class ReflectionMemberInfo<TMemberInfo> : IReflectionMemberInfo<TMemberInfo>

              where TMemberInfo : MethodBase

{

       private TMemberInfo memberInfo;

 

       public ReflectionMemberInfo(TMemberInfo memberInfo)

       {

              this.memberInfo = memberInfo;

       }

 

       public TMemberInfo MemberInfo

       {

              get { return memberInfo; }

       }

 

       public string Name

       {

              get { return memberInfo.Name; }

       }

 

       public object[] GetCustomAttributes(Type attributeType, bool inherit)

       {

              return memberInfo.GetCustomAttributes(attributeType, inherit);

       }

 

       public ParameterInfo[] GetParameters()

       {

              return memberInfo.GetParameters();

       }

}

 

方法使用.NET的反射机制,从一个成员中返回需要的信息,成员被约束为MethodBase类型的成员。当从一个成员中得到这个信息,就可以用它们构造IParameter类型的参数信息了。IParameter保存被依赖对象相应的参数值:

 

public interface IParameter

{

       //参数值类型

       Type GetParameterType(IBuilderContext context);

 

       //参数值

       object GetValue(IBuilderContext context);

}

 

IParameter实现的具体参数类以及他们的继承关系如下(斜体是抽象类):

IParameter

CloneParameter : 实现IClonable接口的参数,如果没有实现这个接口,那么返回原参数值

LookupParameter: 从创建器上下文指定的定位器中获取参数值的参数

KnownTypeParameter: 用于实现那些你已经预先知道参数值类型的参数的助手类

CreationParameter: 使用创建器来创建参数值的参数

DependencyParameter: 依靠依赖注入特性来获取值的参数

ValueParameter: 保存直接被参数使用的值的参数

 

在获取DependencyParameter参数值的时候,DependencyResolver类被设计来处理依赖类型值的获取工作,DependencyResolver类的Resolver方法代码如下:

 

public object Resolve(Type typeToResolve, Type typeToCreate, string id, NotPresentBehavior notPresent, SearchMode searchMode)

{

       if (typeToResolve == null)

              throw new ArgumentNullException("typeToResolve");

       if (!Enum.IsDefined(typeof(NotPresentBehavior), notPresent))

              throw new ArgumentException(Properties.Resources.InvalidEnumerationValue, "notPresent");

 

       if (typeToCreate == null)

              typeToCreate = typeToResolve;

 

       DependencyResolutionLocatorKey key = new DependencyResolutionLocatorKey(typeToResolve, id);

 

       if (context.Locator.Contains(key, searchMode))

              return context.Locator.Get(key, searchMode);

 

       switch (notPresent)

       {

              case NotPresentBehavior.CreateNew:

                     return context.HeadOfChain.BuildUp(context, typeToCreate, null, key.ID);

 

              case NotPresentBehavior.ReturnNull:

                     return null;

 

              default:

                     throw new DependencyMissingException(

                                          string.Format(CultureInfo.CurrentCulture,

                                          Properties.Resources.DependencyMissing, typeToResolve.ToString()));

       }

}

 

方法中代码表明了,如果没有指定typeToCreate参数(null,那么认为同要解决的类型一致。然后根据搜索模式选项在定位器中查找指定的对象,找到就返回,否则根据notPresent参数决定是创建一个新对象,还是返回一个null

看完参数类的代码,我们回头看一下ReflectionStrategy中的获取参数特性的方法,如果一个参数没有施加任何参数特性,那么默认识DependencyAttribute,如果参数被施加了多个参数特性,那么只有第一个特性有效。

下面我们来看具体的三个反射策略以及相应的方针:

ConstructorReflectionStrategy

ConstructorReflectionStrategy要求成员必须处理,它的GetMembers的方法是在已有对象为null同时没有指定方针(existingPolicynull)或者方针是DefualtCreationPolicy的情况下,从要创建的类型中通过反射获取构造器成员信息。如果只有一个构造器,那么就把用这个构造器来创建ReflectionMemberInfo对象,并添加到集合中返回;如果不止一个构造器,则查找施加了InjectionConstructorAttribute特性的构造器,如果有多个这样的构造器,则抛出异常。策略使用的方针是ConstructorPolicy,从构造器信息中构造的参数对象被保存到ConstructorPolicy对象中,并把这个对象保存到创建器上下文的方针表供后续的策略使用。

ConstructorPolicy中保存一个ConstructorInfo对象和该构造器的参数对象集合,AddParameter方法用来添加参数对象到集合中;SelectConstructor方法返回ConstructorInfo对象,如果该对象尚未存在,那么就从方法的Type参数中根据参数对象集合中的参数类型选择一个;GetParameters方法返回参数对象集合中的值。

PropertyReflectionStrategy

PrepertyReflectionStrategy获取成员的方法是通过反射得到要创建类型的所有属性成员。成员是否需要处理的条件是看属性是否施加了ParameterAttribute类型的特性。ParameterAttribute特性在OB中是:CreateNewAttributeDependencyAttribute,有两个内部嵌套的助手类来协助检测工作。添加参数到方针使用的方针是PropertySetterPolicy。如果上下文不存在PropertySetterPolicy对象,那么就创建一个。PropertySetterPolicy是一个实现IPropertySetterPolicy接口的类,保存一个PropertySetterInfo对象的字典集合。PropertySetterInfo实现IPropertySetterInfo接口。

MethodReflectionStrategy

MethodReflectionStrategy获取成员的方法是通过反射得到要创建类型的所有方法成员。成员是否需要处理的条件是成员被施加了InjectionMethodAttribute特性。添加参数到方针使用的方针是MethodPolicyMethodPolicy实现IMethodPolicy接口,使用字典集合保存IMethodCallInfo类型对象。IMethodCallInfo定义了两个方法:GetParametersSelectMethod方法。MethodInfo是实现IMethodCallInfo的具体类,它有八个公共的构造器重载版本,一个私有的构造器。GetParametersSelectMethod方法的实现和构造器反射策略基本一样。MethodInfo内部有一个静态私有的方法ObjectToIParameters用来协助构造器把object[]形式的参数数组转换成IParameter对象数组。

以上是OB在对象预创建阶段所使用的策略和方针。

创建策略

对象的预创建阶段完成之后,紧接着就是创建阶段,这一阶段缺省的策略只有一个(之所以说缺省是因为你可以插入自己的创建策略)。对象的真正创建就是在这一阶段进行的,由于在预创建阶段各个策略对要创建的对象进行了必要的处理加工,所以CreationStrategy的工作相对轻松不少。CreationStrategyBuildUp方法首先检查要创建的对象是否已经存在(通过查看existing参数),如果存在,就调用BuildUpExistingObject方法注册对象,否则,调用BuildUpNewObject方法创建一个新的对象。在BuildUpNewObject方法中,表明只有在方针表中存在ICreationPolicy的方针,对象才被创建,否则抛出异常,创建失败。对象的创建很有意思,先是调用FormatterService.GetUninitializedObject获取一个称为ZeroedObject, 这可以理解未进行任何初始化过程的对象,然后调用RegisterObject方法注册对象,

最后调用InitialzeObject方法对对象进行初始化。对象的注册取决三个条件:第一个条件就是当前定位器存在存在;第二个条件是当前定位器中存在一个ILefetimeContainer对象(生命期容器,我们后面再介绍它);第三个条件就是存在单例方针同时方针表示对象是一个单例对象。任何一条条件得不到满足,RegisterObject方法什么都不做。InitializeObject方法首先获取对象的构造器,如果不存在,是值类型就直接返回,否则抛出异常。然后获取构造器的参数,调用Guard. ValidateMethodParameters检查参数是否和构造器参数类型匹配,不匹配的话,异常抛出。最后执行构造器方法完成对象的初始化工作。

生命期容器是OB用来维护对象的生命周期,该容器是一个集合,并实现了IDisoposable接口,保存在生命期容器中哪些实现了IDisposable接口的对象,在容器Dispose被调用的时候,也全部Dispose。从容器设计的特点来看,容器可用来保存那些需要手工Dispose的对象。

对象创建阶段结束,对象开始被移交到初始化阶段的策略。

属性设置器策略

PropertySetterStrategy策略的任务就是注入属性值(通常是属性依赖注入)。首先确认要创建的对象存在,然后在IPropertySetterPolicy方针存在的情况下,对于方针中的每一个属性设置对象,取出属性信息和属性值,在通过类型匹配检测之后,将值赋予相应的属性。

方法执行策略

方法执行策略和属性设置器策略十分相似,如果存在IMethodPolicy方针,MethodExecutionStrategy将从方针中取出每一个方法信息,然后设置方法参数,最后调用方法。(通常用于方法依赖注入)。

创建器感知策略

BuilderAwareStrategy策略是初始化完成阶段最后一个缺省的策略。创建器感知策略实际上是一个回调策略,一个IBuiderAware的接口被OB提供。任何实现了IBuiderAware接口的对象,在这个阶段会得到一个OnBuilltUp的事件通知。同时在对象被卸载的时候会得到OnTearingDown的通知。激活通知事件就是BuilderAwareStrategy的工作。IBuiderAware定义如下:

 

public interface IBuilderAware

{

       void OnBuiltUp(string id);

 

       void OnTearingDown();

}

 

一路跋涉,终于讲述完了策略和方针在对象创建各个阶段的细节。但是故事并没有结束,后面的故事姑且叫做尾声吧。



下一篇

阅读更多
个人分类: NET C#
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭