领先一步
VMware 提供培训和认证,助您加速进步。
了解更多对于 Spring.NET 来说,这是相当不平凡的一年。在12月的 GA 发布之前,我们经历了两个里程碑版本和两个候选发布版本。1.1 版本的第一个代码块可以追溯到2004年末,当时 Aleks Seovic 开始着手 ASP.NET 框架。总之,这是一个漫长的过程。岁末之际,是回顾过去和现在的自然时机,我想感谢项目其他成员和 Spring.NET 社区的所有贡献和支持。我期待着激动人心的2008年!
Spring.NET 1.1 的功能集相当广泛。包括一个用于依赖注入的 IoC 容器、AOP、ASP.NET 框架、声明式事务管理以及更多。然而,要提高代码结构和可测试性,最具性价比的方法是将依赖注入和 AOP 加入您的开发工具箱。依赖注入是这两种技术中更基础的一种,我想就配置 Spring.NET 容器的选项提供一些额外的信息。
显然,配置容器最常见的方式是通过 XML。XML 虽然提供了极大的灵活性,但也很冗长,每个人都会在酒席上抱怨 XML 配置文件(无论是 Spring 的还是其他的)有多么令人讨厌。编写自定义可以极大地减少冗余,去除许多样板 XML,并呈现专注于特定领域的属性。例如,Spring.NET 为事务管理和 AOP 配置提供了此功能。不过,关于非 XML 配置的好消息是,Spring.NET 将在其下一个版本中添加基于属性的 DI 和对程序集中的带注解类的自动检测。正如您可能预期的那样,所提供的功能将与 Spring Java 中的功能相当相似(参见此处和此处),但会仔细调整以去除多余的 Java 伪影(如 JSR-250 属性),并引入仅在 .NET 中有意义的新功能(如利用方法参数名称进行按名称装配)。
需要记住的一点是,核心容器不依赖于基于 XML 的对象定义。容器有自己的内部对象模型用于这些定义。因此,对象定义可以来自多种格式。据我所读到的,特别吸引人的是使用 DSL 工具包配置异常处理建议。其他有趣的配置方法是使用脚本语言 DSL(请参阅这篇关于 Spring Java + Groovy 集成的帖子)。归根结底,目标是让您可以根据手头的任务在多种配置方法中进行选择。
在当前版本中,有几个关于容器的编程控制和配置的功能似乎并不广为人知。以下是对这些功能的简要概述。我很快会在参考文档中提供更完整的描述。
主要的 IoC 容器接口,IApplicationContext包含方法
根据与该名称关联的对象定义,容器将对传入的实例执行依赖注入。当您需要在运行时响应用户请求来创建对象时,这尤其有用。在这种情况下,您通常会将一些对该情况独特的数据传递给构造函数,然后让容器配置所有用户请求通用的其余对象依赖项。
此功能定义在的子接口上IApplicationContext,即IConfigurableApplicationContext。调用代码如下所示:
((IConfigurableApplicationContext) applicationContext).ObjectFactory.RegisterSingleton("ObjectB", myObjectBInstance);
已注册的对象不会被修改;它只是原样存储在提供的名称下。但是,其他对象可能会将此注册对象引用为依赖项。
按名称检索对象很简单
object o = applicationContext.GetObject("AccountManager")
然后转换为适当的类型。您也可以按类型请求对象
IDictionary dict = context.GetObjectsOfType(typeof (IAccountManager));
这些 API 调用需要一些 TLC,将它们变得通用,并提供一个方便的方法来获取指定类型的单个对象,而不是集合。
类GenericApplicationContext是一个不假定任何特定对象定义格式的 IoC 容器。您可以像这样用嵌入式资源中的基于 XML 的对象定义来加载它:
GenericApplicationContext ctx = new GenericApplicationContext();
IObjectDefinitionReader objectDefinitionReader = new XmlObjectDefinitionReader(ctx); objectDefinitionReader.LoadObjectDefinitions("assembly://MovieFinder/AppContextContribution.xml");
然后,您可以使用以下方式构建的其他对象定义添加到上下文中:ObjectDefinitionBuilder. ObjectDefinitionBuilder提供了一个简单的流畅接口,用于简化对象定义的创建。因此,ObjectDefinitionBuilder允许您将方法调用链接在一起,以创建与您在 Spring XML 中熟悉的元素大致对应的对象定义。
IObjectDefinitionFactory objectDefinitionFactory = new DefaultObjectDefinitionFactory();
ObjectDefinitionBuilder builder = ObjectDefinitionBuilder.RootObjectDefinition(objectDefinitionFactory, typeof(ColonDelimitedMovieFinder));
builder.AddConstructorArg("movies.txt") .SetLazyInit(true);
ctx.RegisterObjectDefinition("AnotherMovieFinder", builder.ObjectDefinition); // process object definitions… ctx.Refresh()
此代码摘自更新的“MovieFinder”示例,您可以从 nightly builds 中下载。顺便说一句,IObjectDefinitionFactory有另一个实现,WebObjectDefinitionFactory,用于 ASP.NET 页面和用户控件,尽管您在这种情况下不太可能使用它。
这里有一个额外的示例,使用TestObject类,它展示了更多的ObjectDefinitionBuilderAPI。
ObjectDefinitionBuilder builder = ObjectDefinitionBuilder.RootObjectDefinition(objectDefinitionFactory, typeof (TestObject));
builder.AddPropertyValue("Age", 22) .AddPropertyValue("Name", "Joe") .AddPropertyReference("Spouse", "Spouse") .SetSingleton(false);
ctx.RegisterObjectDefinition("TestObject", builder.ObjectDefinition);
builder = ObjectDefinitionBuilder.RootObjectDefinition(objectDefinitionFactory, typeof(TestObject));
IList friends = new ArrayList(); friends.Add(new TestObject("Dan", 34)); friends.Add(new TestObject("Mary", 33));
builder.AddPropertyValue("Friends", friends) .AddConstructorArg("Susan") .AddConstructorArg(23) .SetSingleton(false);
ctx.RegisterObjectDefinition("Spouse", builder.ObjectDefinition);
如果您已经有一个基于 XML 的应用程序上下文,您可以将其传递给构造函数,GenericApplicationContext,这意味着它将在后者的父应用程序上下文中作为简单的根/子层次结构存在。您还可以将上下文与ContextRegistry在一个名称下注册,以提供服务定位器风格的查找。
目前,ObjectDefinitionBuilderAPI 相当“字符串化”,这意味着虽然可以注册对象进行“按类型”装配,但比它需要的使用起来更冗长。改进此 API 的“流畅性”是未来版本中另一个需要改进的领域。
好了,各位,今天就到这里。新年快乐!