zoukankan      html  css  js  c++  java
  • IoC Castle Windsor 2.1

    找过一些Windsor教程的文章,博客园上TerryLee有写了不少,以及codeproject等也有一些例子,但都讲的不太明了。今天看到Alex Henderson写的一个系列,非常简单明了。下面是主要的内容

    http://www.cnblogs.com/RicCC/archive/2010/03/30/castle-windsor-ioc-di.html
    Part 1 - Simple configuration
    Part 2 - Array Configuration
    Part 3 - Dictionary configuration
    Part 4 - Switching configurations
    Part 5 - Configuration parameters
    Part 6 - Switching between lifestyles
    Part 7 - Switching implementations
    Part 8 - Referencing implementations by key
    Part 9 - Constructor Injection
    Part 10 - Setter Injection
    Part 11 - Factories
    Part 12 - Decorators
    Part 13 - Injecting Service Arrays
    Part 14 - Startable Facility

     基本示例
    项目要引用Castle.Core.dll、Castle.MicroKernel.dll、Castle.Windsor.dll,引用namespace:
    using Castle.Windsor;
    using Castle.Windsor.Configuration.Interpreters;
    假设有一个服务类TaxCalculator,用来计算税额:

    01 public class TaxCalculator
    02 {
    03     private decimal _rate = 0.125M;
    04     public decimal Rate
    05     {
    06         set { _rate = value; }
    07         get { return _rate; }
    08     }
    09     public decimal CalculateTax(decimal gross)
    10     {
    11         return Math.Round(_rate * gross, 2);
    12     }
    13 }

    计算税额时的代码如下:

    1 WindsorContainer container = new WindsorContainer(new XmlInterpreter());
    2 TaxCalculator calculator = container.Resolve<TaxCalculator>();
    3 decimal gross = 100;
    4 decimal tax = calculator.CalculateTax(gross);
    5 Console.WriteLine("Gross: {0}, Tax: {1}", gross, tax);
    6 Console.ReadKey();

    app.config中的配置如下:

    01 <configuration>
    02     <configSections>
    03         <section name="castle"
    04             type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor" />
    05     </configSections>
    06 <BR>
    07     <castle>
    08         <components>
    09             <component id="taxcalc.service" type="Windsor.Test.TaxCalculator, Windsor.Test">
    10             </component>
    11         </components>
    12     </castle>
    13 </configuration>

    运行程序,计算结果为12.5。可以在配置文件中为Rate属性指定其他值,例如:

    1 <component id="taxcalc.service" type="Windsor.Test.TaxCalculator, Windsor.Test">
    2     <parameters>
    3         <Rate>0.25</Rate>
    4     </parameters>
    5 </component>

    上面的配置指定税率为0.25,因此计算结果为25

     配置
    如果在Windsor容器创建对象实例时,需要注入的属性为数组,而不是上面Rate这样的单个值,怎么配置?
    假如要注入的属性为:

    1 public DateTime[] Holidays
    2 {
    3     get { return _holidays; }
    4     set { _holidays = value; }
    5 }

    则可以如下配置:

    01 <component id="holidays.service" type="Windsor.Test.HolidayService, Windsor.Test" >
    02     <parameters>
    03         <Holidays>
    04             <array>
    05                 <item>2007-12-24</item>
    06                 <item>2007-12-25</item>
    07                 <item>2008-1-1</item>
    08             </array>
    09         </Holidays>
    10     </parameters>
    11 </component>

    如果要注入的属性为Dictionary类型,例如:

    1 public Dictionary<string, string> Aliases
    2 {
    3     get { return _aliases; }
    4     set { _aliases = value; }
    5 }

    配置如下:

    01 <component id="aliases.service" type="Windsor.Test.HolidayService, Windsor.Test">
    02     <parameters>
    03         <Aliases>
    04             <dictionary>
    05                 <entry key="dog">duck</entry>
    06                 <entry key="ate">broke</entry>
    07                 <entry key="homework">code</entry>
    08             </dictionary>
    09         </Aliases>
    10     </parameters>
    11 </component>

    注入的数组、Dictionary属性,我们都不需要初始化创建这个对象,Windsor在注入的时候会新建数组或者Dictionary对象设置给相应属性
    假如,现在通过Windsor配置的服务类比较多,我建立了2份配置,一份用于测试,一份用于生产环境,如何方便的在这2份配置之间切换呢?可以在配置文件中使用include实现,示例如下:

    1 <castle>
    2     <!--<include uri="file://container-debug.config" />-->
    3     <include uri="file://container-live.config" />
    4 </castle>

    include甚至可以包含assembly中的resource(嵌入assembly中的文件)
    另外可以在配置文件中定义属性,然后在其他地方引用这些属性,例如定义属性:

    1 <configuration>
    2   <properties>
    3     <myProperty>Live</myProperty>
    4   </properties>
    5 </configuration>

    使用属性:

    1 <component id="whatConfig.service" type="Windsor.Test.HolidayService, Windsor.Test">
    2     <parameters>
    3         <Configuration>#{myProperty}</Configuration>
    4     </parameters>
    5 </component>

    我们可以针对同一个服务配置多个实现方式,使用id获取各个实现方式的对象实例:

    01 <component id="reader.file1" type="IoC.Tutorials.Part8.FileReader, IoC.Tutorials.Part8">
    02     <parameters>
    03         <FileName>file1.txt</FileName>
    04     </parameters>
    05 </component>
    06 <component id="reader.file2" type="IoC.Tutorials.Part8.FileReader, IoC.Tutorials.Part8">
    07     <parameters>
    08         <FileName>file2.txt</FileName>
    09     </parameters>
    10 </component>

    然后使用配置中的id来获取实例对象:

    1 WindsorContainer container = new WindsorContainer(new XmlInterpreter());
    2 FileReader defaultReader = container.Resolve<FileReader>();
    3 FileReader file1Reader = container.Resolve<FileReader>("reader.file1");
    4 FileReader file2Reader = container.Resolve<FileReader>("reader.file2");

    我们可以使用container.Kernel.HasComponent(string key)方法在代码中判断特定的key是否有注册了服务

     生命周期 Lifestyle, Lifecycle
    Windsor容器中的对象其生命周期有以下几种方式:
    Singleton: 单例模式
    Transient: 临时对象模式,每次都创建一个新对象返回给请求者
    PerThread: 在当前执行线程上为单例模式
    Pooled: 用一个对象池管理请求对象,从对象池中返回对象实例
    Custom: 实现Castle.MicroKernel.Lifestyle.ILifestyleManager或从Castle.MicroKernel.Lifestyle.AbstractLifestyleManager继承,实现自定义的对象生命周期管理
    默认情况下,组件的生命周期为单例模式,可以通过配置文件进行设置:

    1 <component id="taxcalc.service" type="Windsor.Test.TaxCalculator, Windsor.Test" lifestyle="transient" />

    也可以给class添加上[Castle.Core.Transient]、[Castle.Core.PerThread]等属性来设置组件的生命周期,从而忽略配置文件中的设置
    Windsor支持Castle.Core.IInitializable和System.IDisposable接口,如果类实现了IInitializable接口,容器在创建对象实例之后会执行接口的Initialize方法;如果类实现了IDisposable接口,则在销毁对象的时候会执行Dispose方法

     构造器注入
    前面示例我们用的都是setter注入,下面示例使用构造器注入
    有一个用于字符串编码的接口,该接口有2个实现:

    01 public interface IEncoder
    02 {
    03 string Encode(string source);
    04 }
    05 public class NullEncoder : IEncoder
    06 {
    07 public string Encode(string source)
    08 {
    09 return source;
    10 }
    11 }
    12 public class SillyEncoder : IEncoder
    13 {
    14     private char[] _mixedUp = "YACBDFEGIHJLKMONPRSQTUWVXZ".ToCharArray();
    15 <BR>
    16     public string Encode(string source)
    17     {
    18         string upperSource = source.ToUpper();
    19         char[] encoded = new char[source.Length];
    20         for (int i = 0; i < encoded.Length; i++)
    21         {
    22             encoded[i] = MapCharacter(upperSource[i]);
    23         }
    24         return new string(encoded);
    25     }
    26 <BR>
    27     private char MapCharacter(char ch)
    28     {
    29         if ((ch >= 'A') && (ch <= 'Z'))
    30         {
    31             return _mixedUp[ch - 'A'];
    32         }
    33         return ch;
    34     }
    35 }

    然后有一个发送消息的类,其构造函数要求一个IEncode对象:

    01 public class MessageSender
    02 {
    03     private readonly IEncoder _encoder;
    04     private readonly string _from;
    05     public MessageSender(string from, IEncoder encoder)
    06     {
    07         _from = from;
    08         _encoder = encoder;
    09     }
    10     public void SendMessage(string to, string body)
    11     {
    12         Console.WriteLine("to: {0}\r\nfrom: {1}\r\n\r\n{2}", to, _from, _encoder.Encode(body));
    13     }
    14 }

    使用Windsor可以实现:Windsor自动创建一个IEncoder对象提供给MessageSender的构造函数;在配置文件中需要指定from参数的值,否则Windsor将抛出异常无法创建MessageSender对象
    使用的代码如下:

    1 WindsorContainer container = new WindsorContainer(new XmlInterpreter());
    2 MessageSender sender = container.Resolve<MessageSender>();
    3 sender.SendMessage("hammet", "castle is great!");
    4 Console.ReadKey();

    配置如下:

    01 <component id="encoder.silly"
    02     service="Windsor.Test.IEncoder, Windsor.Test"
    03     type="Windsor.Test.SillyEncoder, Windsor.Test" />
    04 <component id="encoder.null"
    05     service="Windsor.Test.IEncoder, Windsor.Test"
    06     type="Windsor.Test.NullEncoder, Windsor.Test" />
    07 <component id="messageSender"
    08     type="Windsor.Test.MessageSender, Windsor.Test">
    09     <parameters>MessageSender
    10         <from>alex@bittercoder.com</from>
    11     </parameters>
    12 </component>

    上面我们有2个IEncoder的实现,我们可以在配置文件中为MessageSender的构造函数指定使用哪一个实现类:

    1 <component id="messageSender"
    2     type="Windsor.Test.MessageSender, Windsor.Test">
    3     <parameters>MessageSender
    4         <from>alex@bittercoder.com</from>
    5         <encoder>${encoder.null}</encoder>
    6     </parameters>
    7 </component>

     Factory Facilities
    我们自己写的类完全由我们自己控制,因此我们可以让他们能够通过Windsor容器管理,但对于某些第三方提供的服务程序,可能构造函数存在额外的依赖性,使得我们无法通过配置直接使用Windsor容器来管理,这种情况下可以使用Windsor的Factory Facilities实现一个工厂,告诉Windsor使用我们的工厂来创建特定的服务对象实例
    比如我们实现了下面这样一个工厂类,用来创建一个ISmsService服务对象:

    01 public class SmsServiceFactory
    02 {
    03     private string _userName;
    04     private string _password;
    05     private int _retryAttempts = 3;
    06 <BR>
    07     public SmsServiceFactory(string userName, string password)
    08     {
    09         _userName = userName;
    10         _password = password;
    11     }
    12     public int RetryAttempts
    13     {
    14         get { return _retryAttempts; }
    15         set { _retryAttempts = value; }
    16     }
    17 <BR>
    18     public ISmsService CreateService()
    19     {
    20         SmsService service = new SmsService();
    21         SmsService.SmsConfig config = new SmsService.SmsConfig();
    22         config.SetCredentials(_userName, _password);
    23         config.RetryAttempts = _retryAttempts;
    24         service.SetConfig(config);
    25         return service;
    26     }
    27 }

    然后我们使用下面的配置,通过Windsor Factory Facilities指定我们所使用的工厂类:

    01 <castle>
    02     <facilities>
    03         <facility
    04             id="factorysupport"
    05             type="Castle.Facilities.FactorySupport.FactorySupportFacility, Castle.MicroKernel" />
    06     </facilities>
    07     <components>
    08         <component id="smsService.Factory"
    09             type="Windsor.Test.SmsServiceFactory, Windsor.Test">
    10             <parameters>
    11                 <userName>joe</userName>
    12                 <password>secret</password>
    13             </parameters>
    14         </component>
    15         <component id="smsService.default"
    16             type="Windsor.Test.ISmsService, Windsor.Test"
    17             factoryId="smsService.Factory"
    18             factoryCreate="CreateService" />
    19     </components>
    20 </castle>

    使用的代码跟其他示例一样:

    1 WindsorContainer container = new WindsorContainer(new XmlInterpreter());
    2 ISmsService smsService = container.Resolve<ISmsService>();
    3 smsService.SendMessage("+465556555", "testing testing...1.2.3");
    Tag标签: Castle,IoC
  • 相关阅读:
    垂直的SeekBar:VerticalSeekBar
    android 获取路径目录方法以及判断目录是否存在,创建目录
    JSON
    列表和导航
    【前端积累】链接
    【前端积累】背景图像和背景替换
    【前段积累】可视化模型
    【前端积累】选择器
    银联支付-产品测试sdk使用流程
    【CSS系列】块级元素和行内元素
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/1888780.html
Copyright © 2011-2022 走看看