4

几个月前,我发现了 PostSharp,有一段时间,它很好。

但随后法律回复说他们不喜欢旧版本的许可证。然后部门告诉我,2.0 的价格高得无法接受(就我们需要的座位数量而言)……我非常失望,但并不灰心。不可能是唯一的这样的框架,我想。

我一直在寻找替代品,但其中大部分要么已死,要么维护不善(特别是在文档部门),要么用于学术用途,要么以上所有(我在看你 Aspect.Net)

然后我发现了 Spring.Net,有一段时间,它很好。

我一直在阅读文档,它继续描绘了似乎是 AOP 必杀技的优越画面。我不再锁定属性来标记我希望代码拦截发生的位置,但它可以在 XML 中进行配置,并且不需要重新编译对其进行更改。伟大的。

然后我查看了示例并在每个使用场景中看到了以下内容:

// Create AOP proxy using Spring.NET IoC container.
IApplicationContext ctx = ContextRegistry.GetContext();
ICommand command = (ICommand)ctx["myServiceCommand"];    
command.Execute();
if (command.IsUndoCapable)
{
    command.UnExecute();
}

为什么前两行代码必须存在?它毁了一切。这意味着我不能简单地为用户提供一组方面和属性或 XML 配置,他们可以通过在适当的方法/类/等上粘贴适当的属性或编辑 XML 中的匹配模式来使用它们。他们必须修改他们的程序逻辑才能完成这项工作!

在这种情况下,有没有办法让 Spring.Net 表现得像 PostSharp?(即用户只需要添加属性/XML 配置,不需要编辑任何方法的内容。

或者,是否有一个值得和有效的替代 PostSharp?我在 SO 上看到过一些类似这样的问题,但他们都没有真正想要取代 PostSharp,他们只是想补充它的功能。我需要全换。

4

2 回答 2

9

简而言之,是的,Spring.Net AOP 可以按照您描述的使用基于 XML 的配置的方式工作:您不必使用最初的两行代码,实际上不鼓励基于代码的配置。您可以仅使用基于 XML 的配置来配置 Spring.Net AOP,这实际上是推荐的方法。

有几个步骤:

  1. 创建您的建议:BeforeAdvice、AroundAdvice、AfterReturningAdvice 和 ThrowsAdvice 是支持的建议类型。AroundAdvice 使用 AOPAlliance 接口,其他使用 Spring.AOP 接口。
  2. 定义你的切入点
  3. 应用切入点和建议

示例配置(从实时配置概括):

  <!-- START Spring.Net AOP -->

  <object id="beforeAdvice" type="MyBeforeAdvice, MyAOP"></object>
  <object id="beforeAdvisor" type="Spring.Aop.Support.DefaultPointcutAdvisor, Spring.Aop">
    <property name="Advice" ref="beforeAdvice" />
  </object>

  <object id="returnsAdvice" type="MyAfterReturningAdvice, MyAOP"></object>
  <object id="returnsAdvisor" type="Spring.Aop.Support.DefaultPointcutAdvisor, Spring.Aop">
     <property name="Advice" ref="returnsAdvice" />
  </object>

  <object id="throwsAdvice" type="MyThrowsAdvice, MyAOP"></object>
  <object id="throwsAdvisor" type="Spring.Aop.Support.DefaultPointcutAdvisor, Spring.Aop">
    <property name="Advice" ref="throwsAdvice" />
  </object>


  <!-- Advise objects -->
  <object type="Spring.Aop.Framework.AutoProxy.ObjectNameAutoProxyCreator, Spring.Aop">
    <property name="ObjectNames">
      <list>
        <value>*Command</value>
        <value>...</value>
      </list>
    </property>
    <property name="InterceptorNames">
      <list>
        <value>beforeAdvisor</value>
        <value>returnsAdvisor</value>
        <value>throwsAdvisor</value>
      </list>
    </property>
  </object> 


  <!-- END Spring.Net AOP -->

编织是在运行时执行的,非常快速且无干扰。

希望这个有用

安德鲁

于 2010-03-25T16:10:50.650 回答
2

我认为您正在寻找查找方法注入功能。

您已经在开始的某个地方加载了 Spring.NET 应用程序上下文。对 Spring.NET 的基于代码的依赖很少。问题是,在任何需要(建议的)服务的地方,您都明确地依赖 Spring.NET 和ContextRegistry.GetContext()..

您可以使用lookup-method通过方法替换来解决这个问题,例如:

创建一个 AbstractCommandFactory:

namespace MyNamespace {
  public abstract class AbstractCommandFactory : ICommandFactory {
    public abstract ICommand getMyCommand();  
  }
}

使用 Spring.NET,您可以getMyCommand返回一个 Spring.NET 对象:

<objects>
  <object id="commandfactory"
          type="MyNamespace.AbstractCommandFactory, MyAssembly">
    <lookup-method name="getMyCommand" object="commands.mycommand" />
  </object>

  <object id="commands.mycommand" 
          type=MyNamespace.MyCommandImplementation, MyAssembly" />
</objects>

现在,当您初始化 Spring.NET 应用程序上下文时,加载此命令工厂并传递引用。当您需要一个 MyCommandImplementation 实例时,您只需从工厂实例请求一个:

public void doSomeWork() {
  // factory is an ICommandFactory
  // instantiated earlier using the explicit context.getObject("commandfactory")
  ICommand myCommand = this.factory.getMyCommand();
  myCommand.Execute();
}

现在您对 Spring.NET 的显式依赖非常小:仅在初始加载 + 工厂实例化时。您的其余代码保持干净。

加分项:您可以更轻松地创建 ICommandFactory/ICommand 模拟来对您的代码进行单元测试。

于 2010-11-05T11:17:42.717 回答