上一篇:Enterprise Library深入解析与灵活应用(6):自己动手创建迷你版AOP框架

在EnteLib中,PIAB(Policy Injection Application Block)和Unity的定位是轻量级的AOP框架和IoC容器(Container)。通过PIAB,我们可以将一些业务无关的crosscutting concern定义于相应的CallHandler中,通过Attribute声明或者配置应用到承载业务逻辑的目标方法上。而通过Unity提供的IoC容器(或者DI容器),即UnityContainer,很好地实现了依赖的动态注入,从而实现了组件之间、模块之间或者服务之间的松耦合。

Unity完全建立在ObjectBuilder2之上,顾名思义,这是一个用于创建对象的基础组件。ObjectBuilder2提供了一种具有高可扩展性的、基于策略(Strategy Based)的对象创建框架,它不仅仅是Unity的基础组件,也是整个EnterLib和Software Factory的基石。而PIAB通过方法调用劫持(Method Call Interception)的机制实现了策略注入(Policy Injection)。PIAB提供了不同的方法劫持机制,最为典型的就是基于TransparentProxy(可以参考我的PIAB系列文章)和代码生成(比如动态生成一个继承自目标类型的子类,通过Override掉相应的Virtual方法实现策略注入;或者动态生成一个实现了目标接口的类型,实现相应的方法实现策略注入)。PIAB需要通过特殊的机制创建可被劫持(Interceptable)对象,而UnityContainer本质上是一个创建对象的容器,如果能够使UnityContainer按照PIAB的要求创建可被劫持(Interceptable)对象,那么就能实现两者之间的集成。(Source Code从这里下载)
***** 该内容需会员回复才可浏览 *****
一、Unity 1.2和EnterLib 4.1如何实现两者的集成

我在本系列的第一篇文章就谈过PIAB和Unity之间的集成问题,当时我们是采用了一个自定以UnityContainerExtension实现的,当时针对的版本是Unity 1.1和EnterLib 3.1。到了Unity 1.2和EnterLib 4.1,Unity已经被广泛地使用到了整个EnterLib内部,微软甚至通过Unity对PIAB进行了彻底的改造。所以,最新的Unity和PIAB中,已经提供了两者的原生集成。

Unity和PIAB两者之间的集成是通过一个特殊的UnityContainerExtension——Microsoft.Practices.Unity.InterceptionExtension.Interception实现的。为了演示Interception的使用,我们创建一个简单的例子。该例子中定义了一服务SyncTimeProvisionService用于实现同步时间的提供,SyncTimeProvisionService实现了接口ISyncTimeProvision。SyncTimeProvisionService本身并不提供具体实现,而是通过另一个组件SyncTimeProvider实现具体的同步时间的返回,SyncTimeProvider实现接口ISyncTimeProvider。

你可以将SyncTimeProvisionService和SyncTimeProvider看成是一个应用中具有依赖关系的两个模块,为了实现两个模块之间的解耦,采用基于接口的依赖是推荐的设计模式。所以,SyncTimeProvisionService并不之间依赖于SyncTimeProvider,而是依赖于SyncTimeProvider的接口ISyncTimeProvider。我们通过Constructor注入实现依赖注入。为了让读者对Unity和PIAB集成的效果具有一个直观的印象,我在SyncTimeProvider 上应用了一个CachingCallHandlerAttribute,如果该CallHandler生效,方法执行的结果将会被缓存,在缓存过期之前,得到的时间将是一样的。相应的代码如下所示:
  1. using System;
  2. namespace Artech.InterceptableUnity
  3. {
  4.    
  5.     public interface ISyncTimeServiceProvision
  6.     {
  7.         DateTime GetCurrentTime();
  8.     }

  9.     public class SyncTimeServiceProvisionService : ISyncTimeServiceProvision
  10.     {
  11.         public ISyncTimeProvider SyncTimeProvider
  12.         { get; private set; }

  13.         public SyncTimeServiceProvisionService([Dependency]ISyncTimeServiceProvider syncTimeServiceProvider)
  14.         {
  15.             this.SyncTimeServiceProvider = syncTimeServiceProvider;
  16.         }

  17.         #region ISyncTimeServiceProvision Members

  18.         public DateTime GetCurrentTime()
  19.         {
  20.             return this.SyncTimeProvider.GetCurrentTime();
  21.         }

  22.         #endregion
  23.     }

  24.     public interface ISyncTimeProvider
  25.     {
  26.         DateTime GetCurrentTime();
  27.     }

  28.     [CachingCallHandler]
  29.     public class SyncTimeProvider : ISyncTimeProvider
  30.     {
  31.         #region ISyncTimeServiceProvider Members

  32.         public DateTime GetCurrentTime()
  33.         {
  34.             return DateTime.Now;
  35.         }

  36.         #endregion
  37.     }
  38. }
复制代码
那么我们就可以通过下面的方式,利用UnityContainer采用基于接口(ISyncTimeServiceProvision)的方式创建SyncTimeServiceProvisionService ,并调用GetCurrentTime方法:
  1. using System;
  2. using System.Threading;
  3. using Microsoft.Practices.EnterpriseLibrary.PolicyInjection.CallHandlers;
  4. using Microsoft.Practices.Unity;
  5. using Microsoft.Practices.Unity.InterceptionExtension;
  6. namespace Artech.InterceptableUnity
  7. {
  8.     class Program
  9.     {
  10.         static void Main(string[] args)
  11.         {
  12.             IUnityContainer container = new UnityContainer();
  13.             container.RegisterType<ISyncTimeServiceProvision, SyncTimeServiceProvisionService>();
  14.             container.RegisterType<ISyncTimeProvider, SyncTimeProvider>();

  15.             container.AddNewExtension<Interception>();
  16.             container.Configure<Interception>().SetDefaultInterceptorFor(typeof(ISyncTimeServiceProvider), new TransparentProxyInterceptor());
  17.             var syncTimeServiceProvision = container.Resolve<ISyncTimeServiceProvision>();
  18.             for (int i = 0; i < 5; i++)
  19.             {
  20.                 Console.WriteLine(syncTimeServiceProvision.GetCurrentTime());
  21.                 Thread.Sleep(1000);
  22.             }

  23.         }
  24.     }
  25. }
复制代码
通过下面的输出,我们看出输出的时间都是相同的,从而证实了CachingCallHandlerAttribute的有效性,进而正式了UnityContainer和PIAB的集成:


 附件: 您所在的用户组无法下载或查看附件
赞助商广告:

TOP