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

1
2
3
4
5
6
7
8
9
10
11
12
13
public class TaxCalculator
{
    private decimal _rate = 0.125M;
    public decimal Rate
    {
        set { _rate = value; }
        get { return _rate; }
    }
    public decimal CalculateTax(decimal gross)
    {
        return Math.Round(_rate * gross, 2);
    }
}

计算税额时的代码如下:

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

app.config中的配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
<configuration>
    <configSections>
        <section name="castle"
            type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor" />
    </configSections>
<br>
    <castle>
        <components>
            <component id="taxcalc.service" type="Windsor.Test.TaxCalculator, Windsor.Test">
            </component>
        </components>
    </castle>
</configuration>

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

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

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

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

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

则可以如下配置:

1
2
3
4
5
6
7
8
9
10
11
<component id="holidays.service" type="Windsor.Test.HolidayService, Windsor.Test" >
    <parameters>
        <Holidays>
            <array>
                <item>2007-12-24</item>
                <item>2007-12-25</item>
                <item>2008-1-1</item>
            </array>
        </Holidays>
    </parameters>
</component>

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

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

配置如下:

1
2
3
4
5
6
7
8
9
10
11
<component id="aliases.service" type="Windsor.Test.HolidayService, Windsor.Test">
    <parameters>
        <Aliases>
            <dictionary>
                <entry key="dog">duck</entry>
                <entry key="ate">broke</entry>
                <entry key="homework">code</entry>
            </dictionary>
        </Aliases>
    </parameters>
</component>

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

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

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

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

使用属性:

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

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

1
2
3
4
5
6
7
8
9
10
<component id="reader.file1" type="IoC.Tutorials.Part8.FileReader, IoC.Tutorials.Part8">
    <parameters>
        <FileName>file1.txt</FileName>
    </parameters>
</component>
<component id="reader.file2" type="IoC.Tutorials.Part8.FileReader, IoC.Tutorials.Part8">
    <parameters>
        <FileName>file2.txt</FileName>
    </parameters>
</component>

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

1
2
3
4
WindsorContainer container = new WindsorContainer(new XmlInterpreter());
FileReader defaultReader = container.Resolve<FileReader>();
FileReader file1Reader = container.Resolve<FileReader>("reader.file1");
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个实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public interface IEncoder
{
string Encode(string source);
}
public class NullEncoder : IEncoder
{
public string Encode(string source)
{
return source;
}
}
public class SillyEncoder : IEncoder
{
    private char[] _mixedUp = "YACBDFEGIHJLKMONPRSQTUWVXZ".ToCharArray();
<br>
    public string Encode(string source)
    {
        string upperSource = source.ToUpper();
        char[] encoded = new char[source.Length];
        for (int i = 0; i < encoded.Length; i++)
        {
            encoded[i] = MapCharacter(upperSource[i]);
        }
        return new string(encoded);
    }
<br>
    private char MapCharacter(char ch)
    {
        if ((ch >= 'A') && (ch <= 'Z'))
        {
            return _mixedUp[ch - 'A'];
        }
        return ch;
    }
}

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class MessageSender
{
    private readonly IEncoder _encoder;
    private readonly string _from;
    public MessageSender(string from, IEncoder encoder)
    {
        _from = from;
        _encoder = encoder;
    }
    public void SendMessage(string to, string body)
    {
        Console.WriteLine("to: {0}\r\nfrom: {1}\r\n\r\n{2}", to, _from, _encoder.Encode(body));
    }
}

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

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

配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
<component id="encoder.silly"
    service="Windsor.Test.IEncoder, Windsor.Test"
    type="Windsor.Test.SillyEncoder, Windsor.Test" />
<component id="encoder.null"
    service="Windsor.Test.IEncoder, Windsor.Test"
    type="Windsor.Test.NullEncoder, Windsor.Test" />
<component id="messageSender"
    type="Windsor.Test.MessageSender, Windsor.Test">
    <parameters>MessageSender
        <from>alex@bittercoder.com</from>
    </parameters>
</component>

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

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class SmsServiceFactory
{
    private string _userName;
    private string _password;
    private int _retryAttempts = 3;
<br>
    public SmsServiceFactory(string userName, string password)
    {
        _userName = userName;
        _password = password;
    }
    public int RetryAttempts
    {
        get { return _retryAttempts; }
        set { _retryAttempts = value; }
    }
<br>
    public ISmsService CreateService()
    {
        SmsService service = new SmsService();
        SmsService.SmsConfig config = new SmsService.SmsConfig();
        config.SetCredentials(_userName, _password);
        config.RetryAttempts = _retryAttempts;
        service.SetConfig(config);
        return service;
    }
}

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<castle>
    <facilities>
        <facility
            id="factorysupport"
            type="Castle.Facilities.FactorySupport.FactorySupportFacility, Castle.MicroKernel" />
    </facilities>
    <components>
        <component id="smsService.Factory"
            type="Windsor.Test.SmsServiceFactory, Windsor.Test">
            <parameters>
                <userName>joe</userName>
                <password>secret</password>
            </parameters>
        </component>
        <component id="smsService.default"
            type="Windsor.Test.ISmsService, Windsor.Test"
            factoryId="smsService.Factory"
            factoryCreate="CreateService" />
    </components>
</castle>

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

1
2
3
WindsorContainer container = new WindsorContainer(new XmlInterpreter());
ISmsService smsService = container.Resolve<ISmsService>();
smsService.SendMessage("+465556555", "testing testing...1.2.3");
 
 
 

IoC - Castle Windsor 2.1的更多相关文章

  1. 小白初学Ioc、DI、Castle Windsor依赖注入,大神勿入(不适)

    过了几天,我又来了.上一篇中有博友提到要分享下属于我们abp初学者的历程,今天抽出点时间写写吧.起初,我是直接去看阳光铭睿的博客,看了一遍下来,感觉好多东西没接触过,接着我又去下了github 里面下 ...

  2. 多个IoC容器适配器设计及性能测试(Castle.Windsor Autofac Spring.Core)

    [转]多个IoC容器适配器设计及性能测试和容器选择 1. 采用的IoC容器和版本 Autofac.2.6.3.862 Castle.Windsor.3.1.0 Spring.Core.2.0.0 2. ...

  3. Castle.Windsor IOC/AOP的使用

    Castle最早在2003年诞生于Apache Avalon项目,目的是为了创建一个IOC(控制反转)框架.发展到现在已经有4个组件了,分别是ActiveRecord(ORM组件).Windsor(I ...

  4. Castle Windsor Ioc 一个接口多个实现解决方案

    介绍 Castle Windsor 是微软的Ioc类库,本文主要介绍解决一个接口多个实现的解决方案 接口和类 以下内容不是真实的实际场景,仅仅是提供解决一个接口多个实现的思路. 业务场景类 先假设有一 ...

  5. 避免Castle Windsor引起的内存泄露

    原文地址: http://nexussharp.wordpress.com/2012/04/21/castle-windsor-avoid-memory-leaks-by-learning-the-u ...

  6. Castle Windsor常用介绍以及其在ABP项目的应用介绍

    最近在研究ABP项目,有关ABP的介绍请看阳光铭睿 博客,ABP的DI和AOP框架用的是Castle Windsor下面就对Castle Windsor项目常用方法介绍和关于ABP的使用总结 1.下载 ...

  7. Aspect Oriented Programming using Interceptors within Castle Windsor and ABP Framework AOP

    http://www.codeproject.com/Articles/1080517/Aspect-Oriented-Programming-using-Interceptors-wit Downl ...

  8. [Castle Windsor]学习依赖注入

    初次尝试使用Castle Windsor实现依赖注入DI,或者叫做控制反转IOC. 参考: https://github.com/castleproject/Windsor/blob/master/d ...

  9. 在ABP项目的应用Castle Windsor

    Castle Windsor常用介绍以及其在ABP项目的应用介绍 最近在研究ABP项目,有关ABP的介绍请看阳光铭睿 博客,ABP的DI和AOP框架用的是Castle Windsor下面就对Castl ...

随机推荐

  1. wordpress博客搬家心得

    更改SSH的连接端口和登录账户 在SSH的配置文件,/etc/ssh/sshd_config中找到Port 22(一般情况下是22, 根据服务器提供商的设置而不同)更改为你自己希望的端口. 至于登录账 ...

  2. Tuning Radio Resource in an Overlay Cognitive Radio Network for TCP: Greed Isn’t Good

    好吧,这是09年七月发布在IEEE Communications Magazine的一篇文章. 核心二个词:overlay cognitive radio network,tcp 讲的是,在认知无线网 ...

  3. CSS3----background:-webkit-gradient()渐变效果

    input[type="button"], input[type="button"]:visited { background: -webkit-gradien ...

  4. Keil C动态内存管理机制分析及改进

    Keil C是常用的嵌入式系统编程工具,它通过init_mempool.mallloe.free等函数,提供了动态存储管理等功能.本文通过对init_mempool.mallloe和free这3个Ke ...

  5. Majority Element 解答

    Solution 1 Naive way First, sort the array using Arrays.sort in Java. Than, scan once to find the ma ...

  6. 独立写作(A or B)

    开头:On contemporary society(一般的背景)/ With the advent of the technologically advanced society (the info ...

  7. WPF-24:绘制正多边形

    一般来说绘制正N边形,使用Blend直接画出来就好.不过可能是博主受WInform影响比较大,比较喜欢使用画出来的图形.如果要绘制正N边形,前面的绘制五角星的公式可以通用的(http://blog.c ...

  8. Apache POI组件操作Excel,制作报表(二)

    本文接上一篇继续探究POI组件的使用.     现在来看看Excel的基本设置问题,以2007为例,先从工作簿来说,设置列宽,因为生成表格列应该固定,而行是遍历生成的,所以可以在工作簿级别来设置列宽, ...

  9. classloader.getresources() 介绍

    ◆普通情况下,我们都使用相对路径来获取资源,这种灵活性比較大. 比方当前类为com/bbebfe/Test.class 而图像资源比方sample.gif应该放置在com/bbebfe/sample. ...

  10. [转]Laravel 4之表单

    Laravel 4之表单 http://dingjiannan.com/2013/laravel-forms/ 创建表单 除了原有的方式创建表单,Laravel提供了一种便捷的方式 <!-- a ...