IoC - Castle Windsor 2.1
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,用来计算税额:
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
|
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的更多相关文章
- 小白初学Ioc、DI、Castle Windsor依赖注入,大神勿入(不适)
过了几天,我又来了.上一篇中有博友提到要分享下属于我们abp初学者的历程,今天抽出点时间写写吧.起初,我是直接去看阳光铭睿的博客,看了一遍下来,感觉好多东西没接触过,接着我又去下了github 里面下 ...
- 多个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. ...
- Castle.Windsor IOC/AOP的使用
Castle最早在2003年诞生于Apache Avalon项目,目的是为了创建一个IOC(控制反转)框架.发展到现在已经有4个组件了,分别是ActiveRecord(ORM组件).Windsor(I ...
- Castle Windsor Ioc 一个接口多个实现解决方案
介绍 Castle Windsor 是微软的Ioc类库,本文主要介绍解决一个接口多个实现的解决方案 接口和类 以下内容不是真实的实际场景,仅仅是提供解决一个接口多个实现的思路. 业务场景类 先假设有一 ...
- 避免Castle Windsor引起的内存泄露
原文地址: http://nexussharp.wordpress.com/2012/04/21/castle-windsor-avoid-memory-leaks-by-learning-the-u ...
- Castle Windsor常用介绍以及其在ABP项目的应用介绍
最近在研究ABP项目,有关ABP的介绍请看阳光铭睿 博客,ABP的DI和AOP框架用的是Castle Windsor下面就对Castle Windsor项目常用方法介绍和关于ABP的使用总结 1.下载 ...
- 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 ...
- [Castle Windsor]学习依赖注入
初次尝试使用Castle Windsor实现依赖注入DI,或者叫做控制反转IOC. 参考: https://github.com/castleproject/Windsor/blob/master/d ...
- 在ABP项目的应用Castle Windsor
Castle Windsor常用介绍以及其在ABP项目的应用介绍 最近在研究ABP项目,有关ABP的介绍请看阳光铭睿 博客,ABP的DI和AOP框架用的是Castle Windsor下面就对Castl ...
随机推荐
- bzoj 3238 Ahoi2013 差异
3238: [Ahoi2013]差异 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 2357 Solved: 1067[Submit][Status ...
- PowerShell3.0中,所有的命令
Get-Command * >> cmd.txt CommandType Name ModuleName ----------- ---- ---------- Alias % -> ...
- Compiled Language vs Scripting Language
Referrence: Blog Compiled Languages Example: C, C++, Java Source code needs to be compiled into bits ...
- ListView之ArrayAdapter
ArrayAdapter 普通的显示listView子项,安卓的内置对象 使用方法: /* ListView :列表 通常有两个职责: a.将数据填充到布局 b.处理点击事件 一个ListView创建 ...
- Java并发编程--Volatile详解
摘要 Volatile是Java提供的一种弱同步机制,当一个变量被声明成volatile类型后编译器不会将该变量的操作与其他内存操作进行重排序.在某些场景下使用volatile代替锁可以减少 ...
- 多线程下不反复读取SQL Server 表的数据
在进行一些如发送短信.邮件的业务时,我们常常会使用一个表来存储待发送的数据,由后台多个线程不断的从表中读取待发送的数据进行发送.发送完毕后再将数据转移到历史表中,这样保证待发送表的数据普通情况下不会太 ...
- [Protractor] Protractor Interactive with elementor
Install: npm install -g elementor Then run: webdriver-manager start Lets say if we want to test 'htt ...
- Swift——(一)为Swift内置类型加入属性
在看苹果官方的Swift Language的时候,遇到实验:Write an extension for the Double type that add an absoluteValue prope ...
- Swift学习之类和结构体的创建
随着一步步的学习,学习到的新知识越来越多了,不管是新的还是旧的,都禁不住时间的堆积,再熟悉的知识点时间久了都会渐渐的忘记,也许这就是人们生活中一种潜在的惰性吧,看似非常熟悉的东西,等到真正要用的时候, ...
- linux重命名
mv A B 将目录A重命名为B mv /a /b /c 将目录/a目录移动到/b下并重命名为c 其实在文本模式中要重命名文件或目录的话也是很简单的,我们只需要使用mv命令就可以了,比如说 ...