我想向你展示我的方法。我只使用 setter 注入。在我们的网络应用程序中,我们经常有许多相互引用的对象。例如,IUserFacade在创建用户时需要IUserState ,而IUserState在删除userState时需要IUserFacade(检查约束)。
例如:
public interface IUserFacade
{
... // User facade Add, Update, Delete
IUserStateFacade { set; }
}
public interface IUserStateFacade
{
...
IUserFacade { set; }
}
实际上,我们有很多具有交叉引用的对象,甚至更复杂。如果每次都创建所有引用的对象,即使在请求期间没有使用,这确实会非常昂贵。我们需要“懒惰”,将代理对象放置在设置器中。
如何做到这一点的方法是:1)StructureMap(IoC 顶部)和 2)Castle(代理顶部)库。下面我将展示此解决方案所需的一些对象片段。更多内容可以在开源项目Catharsis中找到
包装。该对象将由 SM(StructureMap)而不是真正的实现者注入到每个属性中。它是休眠的实现。它正在等待第一个呼叫。如果它永远不会发生(IUserFacade 正在删除用户,在此类请求期间无需访问引用的 IUserStateFacade)此包装器将永远休眠(请求)。一旦触摸,SM 将创建真实对象,Wrapper 会将所有调用传递给该对象。
城堡拦截器:
public class Wrapper : IInterceptor
{
object _lazy;
protected readonly Type Type;
public Wrapper(Type type)
{
Type = type;
}
public void Intercept(IInvocation invocation)
{
if (_lazy.IsNull()) // lazily instantiate the instance
{
_lazy = ObjectFactory.GetInstance(Type);
}
try
{
var method = invocation.Method;
if (method.ContainsGenericParameters)
{
method = method.MakeGenericMethod(invocation.GenericArguments);
}
invocation.ReturnValue = method.Invoke(_lazy, invocation.Arguments);
}
catch (TargetInvocationException ex)
{
// PublishingManager.Publish(.... // publish exception
throw;
}
}
}
代理实例。现在,我们需要一个对象,对 SM 来说清晰易懂。该对象将映射到所有接口(IUserFacade...),而不是返回UserFacade
.
我们也可以在这里使用我们自定义的 AOP 过滤器。
这个 ProxyInstance 将提供真正的实现者类型,并构建 Wrapper。
StructureMap 实例:
公共类 ProxyInstance : Instance { protected readonly ProxyGenerator Factory = new ProxyGenerator(); 受保护的只读类型具体类型;
public ProxyInstance(Type type)
{
ConcreteType = type; // the type for our Wrapper, the real implementation
}
protected override object build(Type pluginType, BuildSession session)
{
var aopFilters =
// my custom way how to inject more AOP filters
AopFilterManager.GetFilters()
// the core for us, one of the interceptors is our Wrapper
.Union(new[] { new Wrapper(ConcreteType) })
.ToArray();
// Castle will emit a proxy for us, but the Wrapper will do the job
var proxy = Factory
.CreateClassProxy(ConcreteType, AopFilterManager.AopOptions, aopFilters);
return proxy;
}
现在只需使用一些标准方法将其映射到 SM 中(我使用的是自定义 ProxyConvention 但它超出了这里的范围)。让我们使用简化的显式映射:
registry
.For<IUserFacade>()
.HybridHttpOrThreadLocalScoped()
.Use(new ProxyInstance(typeof(UserFacade)));
...
此外,我们通过 SM 创建的每个对象都实现了 IService。因此,默认的 setter 注入可以这样设置:
registry.SetAllProperties
(
set => set.TypeMatches
(
type => type
.GetInterfaces()
.Any(i => i.IsEquivalentTo(typeof(IService)))
)
);
从那一刻起,当我们需要使用IUserFacade
(直接 ObjectFactory 调用,或通过 Wrapper 访问)时,我们就会收到真正的实现者。它的所有属性(setter 注入)都将使用我们的 ProxyInstance / Wrapper 预先填充。
如果访问这些属性中的任何一个,例如IUserStateFacade
相同的(上面针对 IUserFacade 描述的)将再次发生。
- 因为生命周期是基于线程或请求的,所以我们在运行时/网络请求中只有一个实现者
- 因为我们在使用 setter 注入时确实注入了 Wrappers,所以循环无限循环没有问题。每次只注入第一级