IoC 容器的一个优点是您可以在对象图的底部交换模拟服务。然而,这似乎在 Spring.Net 中比在其他 IoC 容器中更难做到。这是一些在 Unity 中执行并具有 Spring.Net 代码的代码;
namespace IocSpringDemo
{
using Microsoft.Practices.Unity;
using NUnit.Framework;
using Spring.Context;
using Spring.Context.Support;
public interface ISomeService
{
string DoSomething();
}
public class ServiceImplementationA : ISomeService
{
public string DoSomething()
{
return "Hello A";
}
}
public class ServiceImplementationB : ISomeService
{
public string DoSomething()
{
return "Hello B";
}
}
public class RootObject
{
public ISomeService SomeService { get; private set; }
public RootObject(ISomeService service)
{
SomeService = service;
}
}
[TestFixture]
public class UnityAndSpringDemo
{
[Test]
public void UnityResolveA()
{
UnityContainer container = new UnityContainer();
container.RegisterType<ISomeService, ServiceImplementationA>();
RootObject rootObject = container.Resolve<RootObject>();
Assert.AreEqual("Hello A", rootObject.SomeService.DoSomething());
}
[Test]
public void UnityResolveB()
{
UnityContainer container = new UnityContainer();
container.RegisterType<ISomeService, ServiceImplementationB>();
RootObject rootObject = container.Resolve<RootObject>();
Assert.AreEqual("Hello B", rootObject.SomeService.DoSomething());
}
[Test]
public void SpringResolveA()
{
IApplicationContext container = ContextRegistry.GetContext();
RootObject rootObject = (RootObject)container.GetObject("RootObject");
Assert.AreEqual("Hello A", rootObject.SomeService.DoSomething());
}
[Test]
public void SpringResolveB()
{
// does not work - what to do to make this pass?
IApplicationContext container = ContextRegistry.GetContext();
RootObject rootObject = (RootObject)container.GetObject("RootObject");
Assert.AreEqual("Hello B", rootObject.SomeService.DoSomething());
}
}
}
为了使用 Spring,App.config 文件中需要包含以下内容。显然,这只适用于第一次春季测试,而不是第二次。你可以在配置文件中放置多个弹簧配置吗?如果是这样,语法是什么以及如何访问它们?还是有其他方法可以做到这一点?
<configSections>
<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="config://spring/objects"/>
</context>
<objects xmlns="http://www.springframework.net">
<object name="RootObject" type="IocSpringDemo.RootObject, IocDemo" autowire="constructor" />
<object name="service" type="IocSpringDemo.ServiceImplementationA, IocDemo" autowire="constructor" />
</objects>
</spring>
更新
这是基于Marko Lahma 提供给 Mark Pollack 博客的链接中的代码的部分答案。我通过了上述测试,代码如下:
public static class SpringHelper
{
public static T Resolve<T>(this IApplicationContext context, string name)
{
return (T)context.GetObject(name);
}
public static void RegisterType<T>(this GenericApplicationContext context, string name)
{
context.RegisterType(name, typeof(T));
}
public static void RegisterType(this GenericApplicationContext context, string name, Type type)
{
IObjectDefinitionFactory objectDefinitionFactory = new DefaultObjectDefinitionFactory();
ObjectDefinitionBuilder builder = ObjectDefinitionBuilder.RootObjectDefinition(objectDefinitionFactory, type);
builder.SetAutowireMode(AutoWiringMode.AutoDetect);
context.RegisterObjectDefinition(name, builder.ObjectDefinition);
}
}
...
[Test]
public void SpringResolveA()
{
GenericApplicationContext container = new GenericApplicationContext();
container.RegisterType<RootObject>("RootObject");
container.RegisterType<ServiceImplementationA>("service");
RootObject rootObject = container.Resolve<RootObject>("RootObject");
Assert.AreEqual("Hello A", rootObject.SomeService.DoSomething());
}
[Test]
public void SpringResolveB()
{
GenericApplicationContext container = new GenericApplicationContext();
container.RegisterType<RootObject>("RootObject");
container.RegisterType<ServiceImplementationB>("service");
RootObject rootObject = container.Resolve<RootObject>("RootObject");
Assert.AreEqual("Hello B", rootObject.SomeService.DoSomething());
}
这向我提出了几个问题:
我想将此技术集成到使用常用容器的现有代码中。在这种情况下,为什么我必须使用不同的容器类型
GenericApplicationContext
?如果我想从 app.config 或 web.config 中现有的 spring 配置中读取数据到这个对象中怎么办?它会像通常的上下文一样工作吗?然后我可以用代码在这些注册上写数据吗?如何指定
ISomeService
要创建为单例?我的意思不是向容器提供单例实例,而是容器用于创建实例、解析其构造函数并在需要该类型时使用它。我该怎么做
container.RegisterType<ISomeService, ServiceImplementationA>();
?我想注册类型映射以在构造函数需要该类型的所有情况下使用。具体是
container.RegisterType<ServiceImplementationA>("service");
做什么的?它似乎注册ServiceImplementationA
为实现ISomeService
但从ISomeService
未被提及,因此可能存在歧义。例如,如果ServiceImplementationA
实现了多个接口会怎样。给注册的字符串名称是什么?它不适用于 en 空字符串,但它似乎并不重要。
我是否试图以一种不起作用的方式使用弹簧?我正在尝试像使用其他 IoC 容器一样使用它,但它并不完全有效。