Enterprise Library深入解析与灵活应用(1):通过Unity Extension实现和Policy Injection Application Block的集成

简介:

Enterprise Library是微软P&P部门开发的众多Open source框架中的一个,最新的版本已经出到了4.0。由于接触Enterprise Library已经有很长的一段时间,在实际的项目中使用的频率也很高。对此有了一些积累,希望通过这个新的系列和广大网友一起分享和交流。本系列假设读者已经对Enterprise Library有一定的了解,故而不会对各个Application Block的基本原理和编程模型进行介绍,而把侧重点放在Enterprise Library深层次的实现原理、设计模式的应用、有效扩展和最佳实践上。

 

今天我们讨论的内容是如何通过自定义UnityContainerExtension实现Unity和PIAB的集成,我们假设读者已经对Unity Application Block和Policy Injection Application Block已经有了一定的了解。

一、创建PolicyInjectionStrategy

我们知道Policy Injection Application Block是基于Remoting的原理通过Method Interception的方式实现了AOP(而另一种常见的方式是基于IL Injection)。要使应用在目标对象的CallHandler发挥作用,需用通过PolicyInjecctor(默认为Remoting PolicyInjection)进行对象的创建。而实现Unity和PIAB集成的途径就是让Unity Container使用进行对象的创建。

Unity是建立在ObjectBuilder之上的,而ObjectBuilder是整个Enterprise Library以及P&P其他开源框架(比如Smart Client Software Factory)的基石。ObjectBuilder,顾名思义,就是进行对象创建的组件。而ObjectBuilder进行对象创建的方式是基于策略的(Strategy based object creation),他通过将不同的策略运用到对象创建(或释放回收)的不同的阶段,而从提供了一个功能强大的、极具扩展的对象创建的框架。而要实现我们的目标,首先需要创建自定义的BuilderStrategy:PolicyInjectionStrategy 。

   1: namespace Artech.PolicyInjectionIntegratedInUnity
   2: {
   3:     public class PolicyInjectionStrategy : EnterpriseLibraryBuilderStrategy
   4:     {
   5:         public override void PreBuildUp(IBuilderContext context)
   6:         {
   7:             base.PreBuildUp(context);
   8:             if (context.Policies.Get<IPolicyInjectionPolicy>(context.BuildKey) == null)
   9:             {
  10:                 context.Policies.Set<IPolicyInjectionPolicy>(new PolicyInjectionPolicy(true), context.BuildKey);
  11:             }
  12:         } 
  13:  
  14:         public override void PostBuildUp(IBuilderContext context)
  15:         {
  16:             base.PostBuildUp(context);
  17:             IPolicyInjectionPolicy policy = context.Policies.Get<IPolicyInjectionPolicy>(context.BuildKey);
  18:             if ((policy != null) && policy.ApplyPolicies)
  19:             {
  20:                 policy.SetPolicyConfigurationSource(EnterpriseLibraryBuilderStrategy.GetConfigurationSource(context));
  21:                 context.Existing = policy.ApplyProxy(context.Existing, BuildKey.GetType(context.OriginalBuildKey));
  22:             }
  23:         }
  24:     }
  25: }
  26:  
  27:  

上面就是整个PolicyInjectionStrategy 的定义。通过PreBuildUp在对象创建之前将PolicyInjectionPolicy添加到BuilderContext 的Policy列表中(BuilderContext 为整个对象的创建和生命周期的管理提供context信息)。在PostBuildUp中,将PolicyInjectionPolicy从BuilderContext 中取出,调用ApplyProxy方法将创建的对象通过PolicyInjecctor进行封装,那么调用被封装过的对象,我们的Policy Injection CallHandler就可以发挥其作用了。

注:PolicyInjectionPolicy定了在Microsoft.Practices.EnterpriseLibrary.PolicyInjection dll中,实现了Microsoft.Practices.EnterpriseLibrary.PolicyInjection.ObjectBuilder.IPolicyInjectionPolicy和Microsoft.Practices.ObjectBuilder2.IBuilderPolicy。其ApplyProxy方法实际上就是调用了PolicyInjecctor的Wrap方法。

二、创建PolicyInjectionExtension

有了PolicyInjectionStrategy,我们自定义UnityContainerExtension就显得很简单了,需要做的仅仅是override Initialize方法,创建PolicyInjectionStrategy对象,并将其加入到当前BuilderContext 的Strategie列表中即可。

   1: namespace Artech.PolicyInjectionIntegratedInUnity
   2: {
   3:     public class PolicyInjectionExtension : UnityContainerExtension
   4:     {
   5:         protected override void Initialize()
   6:         {
   7:             base.Context.Strategies.AddNew<PolicyInjectionStrategy>(UnityBuildStage.Initialization);
   8:         }
   9:     }
  10: } 
  11:  

三、通过coding的方式应用PolicyInjectionExtension

我们现在将我们定义的PolicyInjectionExtension使用到实际的场景中,看看它能够像我们希望的那样,调用通过Unity container创建的对象上的方法,其对应的Policy Injection CallHandler能够被正常地执行。我们仍然使用CachingCallHandler和TimeService来做试验。为此,我定义了一个interface(ITimeService) 和他的实现(TimeService ),并通过cusotom attribute的方式在class上应用了CachingCallHandler。

   1: public interface ITimeService
   2: {
   3:         DateTime GetSystemTime();
   4: } 
   5:  
   6: [CachingCallHandler]
   7: public class TimeService : ITimeService
   8: {
   9:     #region IContract Members 
  10:  
  11:     public DateTime GetSystemTime()
  12:     {
  13:             return DateTime.Now;
  14:     } 
  15:  
  16:         #endregion
  17:     }
  18: } 
  19:  

在Console application的Main()中,先创建UnityContainer对象,然后通过AddExtension将我们定义的PolicyInjectionExtension添加到该UnityContainer种,然后进行interface和concrete type匹配关系的注册。最后通过Resolve方法创建ITimeService 对象,并在for循环中以一定的时间间隔(1s)调用GetSystemTime方法。

   1: namespace Artech.PolicyInjectionIntegratedInUnity
   2: {
   3:     class Program
   4:     {
   5:         static void Main(string[] args)
   6:         {
   7:                 IUnityContainer container = new UnityContainer();
   8:                 container.AddExtension(new PolicyInjectionExtension());
   9:                      container.RegisterType<ITimeService, TimeService>();
  10:                 ITimeService instance = container.Resolve<ITimeService>();
  11:                 for (int i = 0; i < 10; i++)
  12:                 {
  13:                     Console.WriteLine(instance.GetSystemTime());
  14:                     Thread.Sleep(1000);
  15:                 }
  16:             }        
  17:     }  
  18: } 
  19:  

因为我们在TimeService 使用了CachingCallHandler,GetSystemTime方法返回的结果将会被缓存。所以输出的时间都是相同的,如下图所示:

image

四、通过configuration的方式应用PolicyInjectionExtension

Unity的主要的目的是实现了DI(dependency injection). DI的目的说白了还是实现松耦合。而送耦合实现的一个主要的途径还是将编译时的依赖转换成运行时的依赖。所以在很多情况下只用通过配置的方式才能真正意义上实现解耦。而Unity的大多数使用场景还是基于configuration方式的。为了实现上一节中通过coding一样的功能,我们定义了如下的Unity配置:

   1: <?xml version="1.0" encoding="utf-8"?>
   2: <configuration>
   3:     <configSections>
   4:         <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,Microsoft.Practices.Unity.Configuration, Version=1.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
   5:     </configSections>   
   6:     <unity>
   7:         <containers>
   8:             <container>
   9:                 <types>
  10:                    <type type="Artech.PolicyInjectionIntegratedInUnity.ITimeService,Artech.PolicyInjectionIntegratedInUnity" mapTo="Artech.PolicyInjectionIntegratedInUnity.TimeService,Artech.PolicyInjectionIntegratedInUnity"/>
  11:                 </types>
  12:                 <extensions>
  13:                     <add type="Artech.PolicyInjectionIntegratedInUnity.PolicyInjectionExtension,Artech.PolicyInjectionIntegratedInUnity" />
  14:                 </extensions>
  15:             </container>
  16:         </containers>
  17:     </unity>
  18: </configuration> 
  19:  

我们通过配置的方式实现了type的注册和extension的添加。有了上面的配置,我们的code进行相应的改动使用unity的配置:

   1: namespace Artech.PolicyInjectionIntegratedInUnity
   2: {
   3:     class Program
   4:     {
   5:         static void Main(string[] args)
   6:         {
   7:             IUnityContainer container = new UnityContainer();
   8:             UnityConfigurationSection unityConfigSection = ConfigurationManager.GetSection("unity") as UnityConfigurationSection;
   9:             unityConfigSection.Containers.Default.Configure(container);
  10:             ITimeService instance = container.Resolve<ITimeService>();
  11:             for (int i = 0; i < 10; i++)
  12:             {
  13:                 Console.WriteLine(instance.GetSystemTime());
  14:                 Thread.Sleep(1000);
  15:             }
  16:         }
  17:     } 
  18: } 
  19:  

运行上面的代码,我们一样可以得到相同的输出:

image

 

 

 

 

 

 


 

Enterprise Library深入解析与灵活应用:
[1] 通过Unity Extension实现和Policy Injection Application Block的集成
[2] 通过SqlDependency实现Cache和Database的同步
[3] 倘若将Unity、PIAB、Exception Handling引入MVP模式
[4] 创建一个自定义Exception Handler改变ELAB的异常处理机制
[5] 创建一个简易版的批处理执行器,认识Enterprise Library典型的配置方式和对象创建方式
[6] 自己动手创建迷你版AOP框架
[7] 再谈PIAB与Unity之间的集成



作者:蒋金楠
微信公众账号:大内老A
微博: www.weibo.com/artech
如果你想及时得到个人撰写文章以及著作的消息推送,或者想看看个人推荐的技术资料,可以扫描左边二维码(或者长按识别二维码)关注个人公众号(原来公众帐号 蒋金楠的自媒体将会停用)。
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
相关文章
|
9月前
|
人机交互 开发工具 vr&ar
使用Unity引擎开发Rokid主机应用的模型交互操作
本文介绍如何使用Unity引擎结合Rokid OpenXR Plugin开发空间计算应用,实现射线交互、模型操作等功能。涵盖环境配置、Demo导入、UI搭建与脚本编写,助力开发者快速构建AR交互应用。
|
10月前
|
人工智能 Java API
Java与大模型集成实战:构建智能Java应用的新范式
随着大型语言模型(LLM)的API化,将其强大的自然语言处理能力集成到现有Java应用中已成为提升应用智能水平的关键路径。本文旨在为Java开发者提供一份实用的集成指南。我们将深入探讨如何使用Spring Boot 3框架,通过HTTP客户端与OpenAI GPT(或兼容API)进行高效、安全的交互。内容涵盖项目依赖配置、异步非阻塞的API调用、请求与响应的结构化处理、异常管理以及一些面向生产环境的最佳实践,并附带完整的代码示例,助您快速将AI能力融入Java生态。
1534 12
|
11月前
|
人工智能 运维 负载均衡
F5发布业界首创集成式应用交付与安全平台,开启ADC 3.0新时代
F5发布业界首创集成式应用交付与安全平台,开启ADC 3.0新时代
491 0
|
11月前
|
人工智能 自然语言处理 分布式计算
AI 驱动传统 Java 应用集成的关键技术与实战应用指南
本文探讨了如何将AI技术与传统Java应用集成,助力企业实现数字化转型。内容涵盖DJL、Deeplearning4j等主流AI框架选择,技术融合方案,模型部署策略,以及智能客服、财务审核、设备诊断等实战应用案例,全面解析Java系统如何通过AI实现智能化升级与效率提升。
881 0
|
缓存 前端开发 定位技术
通义灵码2.5智能体模式实战———集成高德MCP 10分钟生成周边服务地图应用
通义灵码2.5智能体模式结合高德MCP服务,实现快速构建周边服务地图应用。通过自然语言需求输入,智能体自动分解任务并生成完整代码,涵盖前端界面、API集成与数据处理,10分钟内即可完成传统开发需数小时的工作,大幅提升开发效率。
983 0
|
机器学习/深度学习 数据采集 存储
朴素贝叶斯处理混合数据类型,基于投票与堆叠集成的系统化方法理论基础与实践应用
本文探讨了朴素贝叶斯算法在处理混合数据类型中的应用,通过投票和堆叠集成方法构建分类框架。实验基于电信客户流失数据集,验证了该方法的有效性。文章详细分析了算法的数学理论基础、条件独立性假设及参数估计方法,并针对二元、类别、多项式和高斯分布特征设计专门化流水线。实验结果表明,集成学习显著提升了分类性能,但也存在特征分类自动化程度低和计算开销大的局限性。作者还探讨了特征工程、深度学习等替代方案,为未来研究提供了方向。(239字)
360 5
朴素贝叶斯处理混合数据类型,基于投票与堆叠集成的系统化方法理论基础与实践应用
|
机器学习/深度学习 文字识别 监控
安全监控系统:技术架构与应用解析
该系统采用模块化设计,集成了行为识别、视频监控、人脸识别、危险区域检测、异常事件检测、日志追溯及消息推送等功能,并可选配OCR识别模块。基于深度学习与开源技术栈(如TensorFlow、OpenCV),系统具备高精度、低延迟特点,支持实时分析儿童行为、监测危险区域、识别异常事件,并将结果推送给教师或家长。同时兼容主流硬件,支持本地化推理与分布式处理,确保可靠性与扩展性,为幼儿园安全管理提供全面解决方案。
685 3
|
存储 弹性计算 安全
阿里云服务器ECS通用型规格族解析:实例规格、性能基准与场景化应用指南
作为ECS产品矩阵中的核心序列,通用型规格族以均衡的计算、内存、网络和存储性能著称,覆盖从基础应用到高性能计算的广泛场景。通用型规格族属于独享型云服务器,实例采用固定CPU调度模式,实例的每个CPU绑定到一个物理CPU超线程,实例间无CPU资源争抢,实例计算性能稳定且有严格的SLA保证,在性能上会更加稳定,高负载情况下也不会出现资源争夺现象。本文将深度解析阿里云ECS通用型规格族的技术架构、实例规格特性、最新价格政策及典型应用场景,为云计算选型提供参考。
|
人工智能 API 开发者
HarmonyOS Next~鸿蒙应用框架开发实战:Ability Kit与Accessibility Kit深度解析
本书深入解析HarmonyOS应用框架开发,聚焦Ability Kit与Accessibility Kit两大核心组件。Ability Kit通过FA/PA双引擎架构实现跨设备协同,支持分布式能力开发;Accessibility Kit提供无障碍服务构建方案,优化用户体验。内容涵盖设计理念、实践案例、调试优化及未来演进方向,助力开发者打造高效、包容的分布式应用,体现HarmonyOS生态价值。
1006 27
|
数据采集 机器学习/深度学习 存储
可穿戴设备如何重塑医疗健康:技术解析与应用实战
可穿戴设备如何重塑医疗健康:技术解析与应用实战
892 4

推荐镜像

更多