Преимущество контейнера 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>
Обновлять
Вот частичный ответ на основе кода на ссылки, которые Марко Лахма дал на блог Марка Поллака. Я прохожу вышеуказанные тесты со следующим кодом:
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
? Что, если я хочу считывать данные в этот объект из существующей конфигурации Spring в app.config или web.config? Будет ли это работать в обычном контексте? Могу ли я затем записать данные поверх этих регистраций с помощью кода?Как я могу указать, что
ISomeService
должен быть создан как синглтон? Я имею в виду не предоставление экземпляра синглтона контейнеру, а контейнер для создания экземпляра, разрешения его конструктора и использования его, когда этот тип необходим.как я могу сделать эквивалент
container.RegisterType<ISomeService, ServiceImplementationA>();
? Я хочу зарегистрировать сопоставления типов для использования во всех случаях, когда этот тип нужен конструктору.Что именно делает
container.RegisterType<ServiceImplementationA>("service");
? Кажется, чтоServiceImplementationA
регистрируется как реализацияISomeService
, ноISomeService
никогда не упоминается, поэтому может возникнуть двусмысленность. например что, еслиServiceImplementationA
реализовано более одного интерфейса.Для какого строкового имени дается регистрация? Это не будет работать с пустой строкой, но, похоже, не имеет значения, что это такое.
Я пытаюсь использовать Spring так, что это просто не работает? Я пытаюсь использовать его, как другие контейнеры IoC, но он не совсем работает.