我有一小段代码
var idObjects = Spring.Context.Support.ContextRegistry.GetContext()
.GetObjectsOfType(typeof (ICustomInterfaceThatDoesSomething));
foreach (ICustomInterfaceThatDoesSomething icitds in idObjects.Values)
icitds.DoSomething();
有没有办法可以避免这种情况,让spring.net自动将单例注入我声明的属性,就像ICustomInterfaceThatDoesSomething
的数组一样?
我想要这样的事情的唯一原因是因为我想杀死项目的.dll依赖项,这是单点使用。
答案 0 :(得分:2)
您也可以使用method injection:
在sharedLib中:
public class MyService
{
public void ProcessAll()
{
foreach (ICustomInterfaceThatDoesSomething icitds in GetAllImplementers())
icitds.DoSomething();
}
protected virtual IEnumerable<ICustomInterfaceThatDoesSomething> GetAllImplementers()
{
// note that the Spring dependency is gone
// you can also make this method abstract,
// or create a more useful default implementation
return new List<ICustomInterfaceThatDoesSomething>();
}
}
在网络应用中添加一个实现GetAllImplementers()
的类:
public class ServiceLocatorImplementer : IMethodReplacer
{
protected IEnumerable<ICustomInterfaceThatDoesSomething> GetAllImplementers()
{
var idObjects = Spring.Context.Support.ContextRegistry.GetContext()
.GetObjectsOfType(typeof(ICustomInterfaceThatDoesSomething));
return idObjects.Values.Cast<ICustomInterfaceThatDoesSomething>();
}
public object Implement(object target, MethodInfo method, object[] arguments)
{
return GetAllImplementers();
}
}
在Web应用程序的对象定义中配置方法注入:
<objects>
<object name="serviceLocator"
type="WebApp.ServiceLocatorImplementer, WebApp" />
<object name="service" type="SharedLib.MyService, SharedLib">
<replaced-method name="GetAllImplementers" replacer="serviceLocator" />
</object>
</objects>
我觉得使用CommonServiceLocator
会更好(因为服务位置就是你正在做的事情),但是这样使用方法注入,你不需要引入{{ {1}}。
答案 1 :(得分:1)
我会在这里留下这个答案以供将来参考,但我更喜欢我的other answer。
原始答案相当长,而且对问题中的例子非常具体。
我认为没有相当于GetObjectsOfType(...)
的配置。
然而,摆脱Spring.net依赖是不是很容易?
让我看看我是否理解正确:
// sharedLib contains ICustomInterfaceThatDoesSomething
// by "-->" I mean "depends on"
webApp --> Spring.Core, Spring.Web
webApp --> sharedLib
sharedLib --> Spring.Core // only to call GetObjectsOfType(...) on Spring container
我们希望摆脱最后的依赖关系,因为我们希望能够将sharedLib
与另一个DI容器结合使用。在sharedLib
中,我们有一个类需要发出所有ICustomInterfaceThatDoesSomething
实现的信号来执行某些操作。
为此我要创建:
MySomethingManager
{
public MySomethingManager() {}
public MySomethingManager(IMySomethingDoerProvider prov)
{ // init SomethingDoers }
IList<ICustomInterfaceThatDoesSomething> SomethingDoers { get; set; }
void SignalAllToDoSomething()
{
foreach (var doer in Provider.SomethingDoers )
doer.DoSomething();
}
}
IMySomethingDoerProvider
{
IList<ICustomInterfaceThatDoesSomething> GetAll();
}
MySomethingManager
曾用于包含Spring依赖项,但现在它是Spring Free。
现在,在关于sharedLib
:
MySomethingManager
接线时,我有两个选项
MySomethingManager.SomethingDoers
上使用List<ICustomInterfaceThatDoesSomething>
IMySomethingDoerProvider
实现的构造函数注入两者都可以使用Spring和许多其他DI容器完成。您可以使用第一种方法
如果您不介意在配置中列出所有ICustomInterfaceThatDoesSomething
。
如果您需要神奇的GetObjectsOfType(...)
代码,可以使用DI容器的功能来创建IMySomethingDoerProvider
。
使用Spring时,第二种方法需要创建:
MySomethingDoerSpringProvider: IMySomethingDoerProvider
{
IList<ICustomInterfaceThatDoesSomething> GetAll()
{
// use Spring.Context.Support.ContextRegistry.GetContext()
// .GetObjectsOfType(typeof (ICustomInterfaceThatDoesSomething));
}
}
您可以将其置于依赖sharedLib
的项目中。由于您的webApp
已经依赖于Spring.Core,因此您可以将MyProvider
放在那里以便快速入门。
备注的
如果每个实例调用一次DoSomething
,您可以考虑指定一个初始化方法。
答案 2 :(得分:1)
您问题的有趣部分是:如何在库中使用服务定位器函数(例如spring.net的IApplicationContext.GetObjectsOfType(...)
),而不会引入对特定IoC容器的依赖。
正如问题中所述,这很有用,因为我们希望构建不强制使用者使用特定IoC容器的库。但是,我们仍然希望使用 IoC容器,因为它简化了我们库的开发。杰里米·米勒在帖子"It’s time for IoC Container Detente"中很好地描述了这种困境。
他的博客帖子导致small project on codeplex called CommonServiceLocator。该项目为服务定位指定IServiceLocator interface,由许多流行的IoC容器实现,包括Spring.NET。
IServiceLocator
定义了IEnumerable<TService> GetAllInstances<TService>();
方法,基本上是您问题中要求的方法。
当您的库需要服务定位器功能时,您可以依赖CommonServiceLocator库,您和其他消费者可以使用您选择的IoC容器连接它。
猜猜:Spring.NET适配器使用IEnumerable<TService> GetAllInstances<TService>();
实现GetObjectsOfType(serviceType);
。
答案 3 :(得分:0)
感谢Marijin的洞察力已经被钉死了!
首先考虑这个通用实用程序类
public class ServiceLocatorImplementer : IMethodReplacer
{
private readonly Type _forType;
public ServiceLocatorImplementer(Type forType)
{
this._forType = forType;
}
protected IEnumerable GetAllImplementers()
{
var idObjects = Spring.Context.Support.ContextRegistry.GetContext()
.GetObjectsOfType(_forType);
return idObjects.Values;
}
public object Implement(object target, MethodInfo method, object[] arguments)
{
return GetAllImplementers();
}
}
使用此配置示例
声明它<object id="FindInterfaceUsages" type="ServiceLocatorImplementer, SpringDependendAssembly">
<constructor-arg name="forType">
<object type="System.Type" factory-method="GetType">
<constructor-arg type="string" name="typeName" value="Foo.Bar.IChe, NONSpringDependendAssembly" />
<!-- i use the strict overload -->
<constructor-arg type="bool" name="throwOnError" value="true" />
<constructor-arg type="bool" name="ignoreCase" value="false" />
</object>
</constructor-arg>
</object>
<object id="MightyPirate" type="Foo.Pirates, NONSpringDependendAssembly">
<replaced-method name="GetAllICheImplentations" replacer="FindInterfaceUsages" />
</object>
最后注入所需的目标
这种方法的优点在于,在您实际执行GetAllICheImplentations()
之前,基础GetObjectsOfType 不将被调用(除非您尝试在spring init期间执行它而不是好好预示)