spring.net、castle windsor、unity实现aop、ioc的方式和简单区别
本文不讲这3大框架的内部实现原理,只是提供了一个demo,分别实现了它们实现注入属性、拦截消息的例子,以写日志为例,写日志方式用异步还是同步ILogType作为写日志方式,注入日志存放地方ILogStore来演示基本的aop、ioc功能。spring.net用的1.3.1,官网http://www.springframework.net/,castle windsor用的2.5.2,官网http://www.castleproject.org/,unity用的2.0,它是微软开源项目,可在http://unity.codeplex.com/下载,该demo用的这3大框架里的依赖注入容器均为最新版本,部分配置等实现方式有细微变化,中文资料很少找,我也作为入门学习,做一个技术备份吧。
之前对spring.net熟悉点,中文资料也比较多,比如刘冬的博客http://www.cnblogs.com/GoodHelper。spring.net项目里它封装和扩展了很多其他项目,比如常用的NHibernate,windows消息队列,作业调度,asmx,wcf服务等,castle项目也是相当的庞大,monorail,activerecord,windsor,dynamicproxy等,terrylee好几年前就写过系列博文activerecord和windsor的介绍,http://www.cnblogs.com/Terrylee/archive/2006/04/28/387503.html,unity是微软企业库EntLib发展中演变出来的依赖注入容器,artech的系列文章http://www.cnblogs.com/artech/tag/Unity/ kyo-yo的系列文章 http://www.cnblogs.com/kyo-yo/tag/Entlib/等都是相当有技术含量的。
先看下整个demo的结构:
本程序通过写日志的方式来说明注入过程,ILogType申明写日志的方式,IlogStore申明日志存放方式:
/// http://lawson.cnblogs.com
/// </summary>
public interface ILogType
{
ILogStore Logs { get;set;}
void Log(string content);
}
/// http://lawson.cnblogs.com
/// </summary>
public interface ILogStore
{
void Log(string content);
}
DirectLogType用来表示日志直接同步存放,ThreadLogType表示日志异步存放(这里简单处理直接new线程处理了),ConsoleLog表示日志存放控制台展现,TextLog表示日志用文本文档存放。
下面看Spring.net的代码,为了直接在Main函数看到所有代码,这里直接在Main里从容器获取对象:

static void Main(string[] args)
{
IApplicationContext ctx = ContextRegistry.GetContext();
ILogType logtype = (ILogType)ctx.GetObject("LogType");
//ILogType logtype = SpringObjectManager.GetObject<ILogType>("LogType");
logtype.Log("log spring test");
Console.ReadKey();
}
输出结果如下:
从代码里看不到多余的代码,它是通过配置文件注入了consoleLog,并且添加了前置后置环绕通知实现的,配置文件如下:

<sectionGroup name="spring">
<section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core" />
<section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core" />
</sectionGroup>
</configSections>
<spring>
<context>
<resource uri="file://objects.xml" />
</context>
</spring>

<objects xmlns="http://www.springframework.net"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.net
http://www.springframework.net/xsd/spring-objects.xsd">
<object id="LogType" type="Common.ThreadLogType, Common" > <!--singleton="false" lazy-init="false"-->
<property name="Logs" ref="ConsoleLog"/>
</object>
<object id="ConsoleLog" type="Spring.Aop.Framework.ProxyFactoryObject">
<property name="Target">
<object type="Common.ConsoleLog, Common">
</object>
</property>
<property name="InterceptorNames">
<list>
<value>beforeAdvice</value>
<value>aroundAdvice</value>
<value>afterAdvice</value>
<value>throwsAdvice</value>
</list>
</property>
</object>
<object id="beforeAdvice" type="SpringNetConsole.Advice.BeforeAdvice, SpringNetConsole" />
<object id="aroundAdvice" type="SpringNetConsole.Advice.InvokeAdvice, SpringNetConsole" />
<object id="afterAdvice" type="SpringNetConsole.Advice.AfterAdvice, SpringNetConsole" />
<object id="throwsAdvice" type="SpringNetConsole.Advice.ExceptionAdvice, SpringNetConsole" />
</objects>
spring.net的环绕通知通过配置后继承AopAlliance.Intercept.IMethodInterceptor接口的public object Invoke(IMethodInvocation invocation)即可拦截,前置后置通知继承Spring.Aop下的IMethodBeforeAdvice,IAfterReturningAdvice接口实现拦截,具体配置文件的说明可以查看相关文档或者spring.net专题的详细说明。
Castle的最新版本和以前有一定的差别,Castle.core已经封装了以前的DynamicProxy的代码,windsor在ioc方面的配置方式差不多,思路都一样的,引用其他对象,它的关键字符是$,如
<parameters>
<Logs>${Log}</Logs>
</parameters>
</component>
它也有自己的环绕通知和前置后置通知,环绕通知Castle.DynamicProxy.IInterceptor,前置后置通知的拦截只在一个类里Castle.DynamicProxy.StandardInterceptor。
Unity用起来,和官方资料看起来,感觉更希望大家通过写代码的方式注入对象和拦截对象,但是我更喜欢配置文件注入的方式,因此也用配置文件来注入对象:

<unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
<alias alias="singleton" type="Microsoft.Practices.Unity.ContainerControlledLifetimeManager, Microsoft.Practices.Unity" />
<sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension,
Microsoft.Practices.Unity.Interception.Configuration" />
<container name="abc">
<extension type="Interception" />
<register type="IInterceptionBehavior" mapTo="UnityConsole.Advice.MyInterceptionBehavior,UnityConsole"
name="MyInterception"></register>
<register type="Common.ILogType, Common" mapTo="Common.ThreadLogType, Common">
<property name="Logs">
<dependency name="regLogs"></dependency>
</property>
</register>
<register name="regLogs" type="Common.ILogStore, Common" mapTo="Common.ConsoleLog, Common">
<interceptionBehavior name="MyInterception"/>
<interceptor type="InterfaceInterceptor"/>
</register>
</container>
</unity>
具体配置方式可以查询相关文档,有意思的是我没有发现它明确的前置后置通知,只有一个通用的环绕通知拦截,Microsoft.Practices.Unity.InterceptionExtension.IInterceptionBehavior接口内的public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext),通过注入后,继承它可以拦截到消息的执行。
但可以通过继承它的Microsoft.Practices.Unity.UnityContainerExtension扩展,完成事件的拦截,如artech的文章-IoC+AOP的简单实现 :http://www.cnblogs.com/artech/archive/2010/09/01/1815221.html,或者国外的http://www.machinaaurum.com.br/blog/post/AOP-With-Unity-20.aspx3篇文章,这个我也在学习中,还不是很熟。
这3大框架都是相当庞大的系统,需要慢慢学习,根据项目需要应用他们,也许会发现更合理更合适的实现方式。本篇博文只是简单的对3大容器完成aop、ioc的简单讲解,由于我现在对他们也是了解皮毛,文章或者程序有不对的地方,欢迎提出,我也可以多学习学习。
本demo源代码如下:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· .NET周刊【3月第1期 2025-03-02】
· [AI/GPT/综述] AI Agent的设计模式综述