惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Microsoft Azure Blog
Microsoft Azure Blog
H
Hacker News: Front Page
A
About on SuperTechFans
云风的 BLOG
云风的 BLOG
aimingoo的专栏
aimingoo的专栏
Martin Fowler
Martin Fowler
博客园 - 叶小钗
Last Week in AI
Last Week in AI
Recent Announcements
Recent Announcements
P
Palo Alto Networks Blog
Webroot Blog
Webroot Blog
Hacker News: Ask HN
Hacker News: Ask HN
IT之家
IT之家
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
T
Threat Research - Cisco Blogs
C
CERT Recently Published Vulnerability Notes
Google DeepMind News
Google DeepMind News
Hugging Face - Blog
Hugging Face - Blog
H
Help Net Security
P
Privacy & Cybersecurity Law Blog
C
Cisco Blogs
罗磊的独立博客
The GitHub Blog
The GitHub Blog
M
MIT News - Artificial intelligence
人人都是产品经理
人人都是产品经理
The Cloudflare Blog
Y
Y Combinator Blog
AWS News Blog
AWS News Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
K
Kaspersky official blog
博客园 - 司徒正美
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Security Archives - TechRepublic
Security Archives - TechRepublic
The Last Watchdog
The Last Watchdog
Jina AI
Jina AI
MyScale Blog
MyScale Blog
TaoSecurity Blog
TaoSecurity Blog
大猫的无限游戏
大猫的无限游戏
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Cisco Talos Blog
Cisco Talos Blog
美团技术团队
T
Tor Project blog
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
博客园 - 【当耐特】
博客园 - 聂微东
V2EX - 技术
V2EX - 技术
I
Intezer
V
Visual Studio Blog
酷 壳 – CoolShell
酷 壳 – CoolShell

博客园 - Peter Wang

SharePoint 备忘录 查找ContentType的依赖项 Different users – Calendar Audience Targeting Guide SharePoint 2010 Audit log report SharePoint workspace 2010同步功能 SharePoint 2010 bug sharepoint 引用不起作用 整合Bing Maps silverlight performance tip DotNet软件测试实战技术 VSTS 架构版share 敏捷开发中的项目管理利器-Mingle Castle揭密2----IOC(1) Castle揭密2----IOC(3) Castle揭密1--前言 概念回顾--MDA 概念回顾---中间件(IDC) 实现Web Service依赖倒置 SQL Server 索引结构及其使用(四) SQL Server 索引结构及其使用(三)
Castle揭密2----IOC(2)
Peter Wang · 2008-08-28 · via 博客园 - Peter Wang

   Castle IOC是Castle的核心和灵魂。有一句话是这么说的,如果要理解castle和spring这样的框架,必须首先理解其IOC。当然,如果停留在使用层次那就不需要了。本章帮你一起揭密Castle IOC本质。

首先来看个例子。假设有这么个需求,实现给一个通知功能,把一些消息通知一群朋友。需求分析如下:

image

参与者,接受者,通知内容,通知方式,消息服务协调者(manager,service)

1. 参于actor 操作员(登录者,管理员等) 和 朋友

简单期间,客户用string array实现

String[] friendsList = new String[] { "john", "steve", "david" };

2. 通知形式。为了扩充通知方式,抽出一接口先。

public interface IEmailSender
{
    void Send(String from, String to, String message);
}

实现smtp方式,注意,fake方法。示意而已。

注意,这里实现了三个构造函数。

   1: public class SmtpEmailSender : IEmailSender     
   2:    {
   3:  
   4:        #region IEmailSender Members
   5:  
   6:        public virtual void Send(String from, String to, String message)
   7:        {
   8:            Console.WriteLine("Sending e-mail from {0} to {1} with message '{2}'", from, to, message);
   9:        }
  10:  
  11:        #endregion
  12:  
  13:        private String host = "my.default.host";
  14:        private int port = 25;
  15:  
  16:        public SmtpEmailSender()
  17:        {
  18:        }
  19:  
  20:        public SmtpEmailSender(String host, int port)
  21:        {
  22:            this.host = host;
  23:            this.port = port;
  24:        }
  25:        private String[] _hosts;
  26:  
  27:        public SmtpEmailSender(String[] hosts)
  28:        {
  29:            if (hosts == null) throw new ArgumentNullException("hosts");
  30:            if (hosts.Length == 0) throw new ArgumentException("hosts is empty");
  31:  
  32:            _hosts = hosts;
  33:        }
  34:  
  35:    }

3. 通知内容,为了通知很丰富格式多样的内容,抽出一模板接口,用不同方法实现各种内容。例如纯文本的,html的,特殊模板语法的等

public interface ITemplateEngine
{
 
    String Process(String templateName);
}

实现一dummy NVelocity类,只返回一简单字符串而已

public class NVelocityTemplateEngine :ITemplateEngine   
{
    public NVelocityTemplateEngine()
    {
    }
 
    #region ITemplateEngine Members
 
    public string Process(string templateName)
    {
        return "some content";
    }
 
    #endregion
}

4. 抽象出通知内容和通知方式后,该主角出场。主角是一个通知service,通过使用IEmailSender发送ITemplateEngine 返回的内容给我的朋友,此功能封装在里INewsletterService,定义了Dispatch方法作为分发service。

public interface INewsletterService
{
    void Dispatch(String from, String[] targets, String messageTypeName);
}

SimpleNewsLetterService实现了这一服务,定义了两个构造,第二个构造是为了测试对sometype的依赖用,没有他意。这里聚合依赖接口IEmailSender和ITemplateEngine,不是具体类型。这里通过构造器注入的方式实现解藕。

   1: public class SimpleNewsLetterService :INewsletterService    
   2:    {
   3:  
   4:  
   5:        private IEmailSender _sender;
   6:        private ITemplateEngine _templateEngine;
   7:  
   8:        public SimpleNewsLetterService(IEmailSender sender, ITemplateEngine templateEngine)
   9:        {
  10:            _sender = sender;
  11:            _templateEngine = templateEngine;
  12:        }
  13:  
  14:        public SimpleNewsLetterService(Type sometype, IEmailSender sender, ITemplateEngine templateEngine)
  15:        {
  16:            if (sometype == null) throw new ArgumentNullException("sometype");
  17:  
  18:            _sender = sender;
  19:            _templateEngine = templateEngine;
  20:        }
  21:        public void Dispatch(String from, String[] targets, String messageTypeName)
  22:        {
  23:            String message = _templateEngine.Process(messageTypeName);
  24:    
  25:            foreach(String target in targets)
  26:            {
  27:                _sender.Send(from, target, message);
  28:            }
  29:        }
  30:    }

5. 客户端调用如下。(请引入相应dll,我使用的是build 936,目前新的castle还没有release,较早的release是1.0 Release Candidate 3 - September 20, 2007 ,封装的是nhibernate1.2。

   1: IWindsorContainer container = new WindsorContainer();   
   2:            container.AddComponent("mailSender", typeof (IEmailSender), typeof (SmtpEmailSender));
   3:            container.AddComponent("NVelocityEngine", typeof (ITemplateEngine), typeof (NVelocityTemplateEngine));
   4:            container.AddComponent("newLetter", typeof (INewsletterService), typeof (SimpleNewsLetterService));
   5:  
   6:  
   7:  
   8:            String[] friendsList = new String[] { "john", "steve", "david" };
   9:  
  10:            INewsletterService newsLetterService = container["newLetter"] as INewsletterService ;
  11:            newsLetterService.Dispatch("peter", friendsList, "hello world");

解释

1:首先new一castle IOC容器WindsorContainer,放入三个component

2:调用的时候通过AddComponent方法,有很多重载。其中一个,AddComponent(string key, System.TypeserviceType , System.Type classType), serviceType是抽象服务type,定义了基本契约。可以是类,接口,抽象类等。classType是实现类 。key必须唯一,相同classType和serviceType不同key可以加入。

3:获取容器中的的组件可以通过Key或者service Type。

4:最后一个AddComponent调用完,容器自动确定IEmailSender,ITemplateEngine ,INewsletterService的依赖关系,并且通过依赖注入(这里是构造器注入)将ITemplateEngine和IEmailSender的实现注入给INewsletterService

5:这里SmtpEmailSender和NVelocityTemplateEngine是调用的默认构造函数,SimpleNewsLetterService是调用的public SimpleNewsLetterService(IEmailSender sender, ITemplateEngine templateEngine)。

问题来了:

1:容器怎么知道mailSender,NVelocityEngine和newLetter的依赖关系?

2:容器怎么会调用到SimpleNewsLetterService的构造函数将mailSender和templateEngine传入的?

3:容器如何管理组件生命周期的?

4:容器对其它注入方式如何支持?如Type3-setter

带着这些问题,让我们来解读大师们的源码,在这里我们领略下成功的open source框架架构设计所带来的乐趣。

未完,待续。。。

附:依赖注入可以通过代码设置,更多的是通过配置文件注入。Spring主要就是配置注入。关于xml配置的在开发中的优缺点,xml配置是否过渡使用,动态语言带来的革新对配置的冲击和影响,有兴趣可以另外探讨

配置文件示范:     

Config.XML如下,细节不解释了。看看注释就明白了。另外不管是spring,castle还是microsoft enterprise library都对sectionHandler进行扩充,为了便于在.net开发中在web.config或者app.config进行配置注入。例如Castle.Windsor.Configuration.AppDomain.CastleSectionHandler:

<section name="castle" type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor"/>

<castle>

。。。

</castle>

注意下文的对array参数和list的配置,更多的还有泛型type的配置等,依赖的配置。如<sender>${smtpemailsender}</sender>,这里是揭示原理篇,更多使用请参考其它文章或者我的.net solution架构汇总。

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
        <!-- Please note the usage of service and type attributes.
      Windsor will automatically installs the components and 
      facilities with a type attribute (and optionally service for components)-->
        <!--This is a facility configuration example:
      <facilities>
      <facility id="nhibernate" type="Full Type Name, AssemblyName">
      </facility>
      </facilities>
      -->
  <components>
    <component id="smtpemailsender"
    service="CastleIOC.IOC.Component.IEmailSender, CastleIOC"
    type="CastleIOC.IOC.Component.SmtpEmailSender, CastleIOC">
      <parameters>
        <hosts>
          <!-- The following nodes will be converted to an array of String 
          which is what the component expects. If the component expected
          an int[], the MicroKernel would try to convert each element 
          as well.The MicroKernel also supports
          - Dictionaries
          <dict keyType="System.String, mscorlib" valueType="System.Int32, mscorlib">
          <item key="key1">1</item>
          <item key="key2">2</item>
          </dict>
          - Lists 
          <list type="typetobeconverted">
          <item>item1</item>
          <item>item2</item>
          </list>
-->
          <array>
            <elem>MyFirstHost</elem>
            <elem>OtherHost</elem>
          </array>
        </hosts>
      </parameters>
    </component>
    <component id="newLetter"
    service="CastleIOC.IOC.Component.INewsletterService, CastleIOC"
    type="CastleIOC.IOC.Component.SimpleNewsLetterService, CastleIOC">
      <parameters>
        <!-- This argument will be converted to a System.Type        -->
        <sometype>System.Collections.IList, mscorlib</sometype>
        <!-- Here we're overriding which IEmailSender implementation 
this component should use                               -->
        <sender>${smtpemailsender}</sender>
        <!-- Same thing for ITemplateEngine                          -->
        <templateEngine>${nvelocityengine}</templateEngine>
      </parameters>
    </component>
    <component id="nvelocityengine"
    service="CastleIOC.IOC.Component.ITemplateEngine, CastleIOC"
    type="CastleIOC.IOC.Component.NVelocityTemplateEngine, CastleIOC" />
  </components>
</configuration>