Ненавязчивый АОП с Spring.Net - PullRequest
       45

Ненавязчивый АОП с Spring.Net

3 голосов
/ 02 февраля 2012

Я пытаюсь добавить протоколирование в методы, украшенные атрибутом , используя Spring.Net для AOP .

Шаг 1: Ссылка 'Spring.Core', 'Spring.Aop', 'Common.Logging'

Шаг 2: Создайте совет:

using AopAlliance.Intercept;

namespace MyApp.Aspects
{
    public class LoggingAdvice : IMethodInterceptor
    {
      public object Invoke(IMethodInvocation invocation)
      {
        //todo: log started
        object rval = invocation.Proceed();
        return rval;
        //todo: log finished
      }
    }
}

Шаг 3. Создание атрибута:

using System;

namespace MyApp.Aspects
{
  public class LoggingAttribute : Attribute
  {
  }
}

Шаг 4. Редактирование web.config

<configuration>
  <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.springfrmework.net">

      <object id="loggingAdvice" type="MyApp.Aspects.LoggingAdvice, MyApp"></object>
      <object id="loggingAdvisor" type="Spring.Aop.Support.DefaultPointcutAdvisor, Spring.Aop">
        <property name="Advice" ref="loggingAdvice" />
      </object>

      <object type="Spring.Aop.Framework.AutoProxy.AttributeAutoProxyCreator, Spring.Aop">
        <property name="AttributeTypes" value="MyApp.Aspects.LoggingAttribute"/>
        <property name="InterceptorNames" value="loggingAdvisor"/>
      </object>

    </objects>
  </spring>
</configuration>

Шаг 5. Украсьте метод атрибутом:

using System.Web.Mvc;

namespace MyApp.Controllers
{
  public class MyController : Controller
  {
    [Logging]
    public ActionResult DoStuff()
    {
      //todo: implement
    }
  }
}

совет никогда не срабатывал . Чего мне не хватает?

Ответы [ 2 ]

7 голосов
/ 02 февраля 2012

Это связано с тем фактом, что контроллер создан и затем сам вызывает DoStuff() для него. Контроллер, очевидно, не держит прокси для себя и, следовательно, вызов DoStuff() не перехватывается Spring.Net AOP.

Как Тобсен упоминает в своем ответе, вам придется взять контроллер с весны, иначе перехват не состоится. Я предполагаю, что вы используете здесь поддержку Spring mvc для создания контроллеров, но это не ясно из вашего вопроса, и вы, возможно, оставили его.

Как перехватить методы действия на контроллерах MVC 3

Резюме

Подробности и пример приведены ниже.

  1. Используйте InheritanceBasedAopConfigurer
  2. Объявите методы, которые вы хотите перехватить, как виртуальные
  3. Настройте перехватчики

Механизм перехвата по умолчанию Spring не работает ...

Когда в приложение MVC делается запрос, то из URL-адреса запроса контроллер MVC выбирает контроллер. На этом контроллере вызывается метод Execute(), который, в свою очередь, отвечает за вызов методов действия. Важно понимать, что методы действия всегда вызываются из контроллера .

Spring.NET AOP использует динамическое переплетение. По умолчанию во время выполнения прокси создается для объектов, для которых в конфигурации объявлены aop советники. Этот прокси перехватывает вызовы и перенаправляет вызовы целевому экземпляру. Это делается при проксировании интерфейсов и классов (используя proxy-target-type="true") . Когда целевой объект сам вызывает метод, он не будет делать это через прокси-пружину, а метод не перехватывается . Вот почему механизм aop по умолчанию не работает для контроллеров mvc.

... но использование InheritanceBasedAopConfigurer делает трюк

Для перехвата вызовов методов действия вы должны использовать InheritanceBasedAopConfigurer. Это создаст прокси на основе наследования, которое не делегирует целевому объекту, вместо этого рекомендация по перехвату добавляется непосредственно в тело метода перед вызовом метода базового класса.

Обратите внимание, что для работы этого метода перехвата методы должны быть виртуальными.

Работает следующая конфигурация xml:

<!-- 
When not specifying an object id or name, 
spring will assign a name to it like [typename]#[0,1,2,..]  
-->  
<object type="MyApp.Controllers.HomeController, MyApp" 
        singleton="false" />

<object id="myInterceptor" type="Spring.Aop.Support.AttributeMatchMethodPointcutAdvisor, Spring.Aop">
  <property name="Attribute" value="MyApp.MyAttribute, MyApp" />
  <property name="Advice">
    <object type="MyApp.MyAdvice, MyApp" />
  </property>
</object>

<object type="Spring.Aop.Framework.AutoProxy.InheritanceBasedAopConfigurer, Spring.Aop">
  <property name="ObjectNames">
    <list>
      <value>*Controller#*</value>
    </list>
  </property>
  <property name="InterceptorNames">
    <list>
      <value>myInterceptor</value>
    </list>
  </property>
</object>

Рабочий пример доступен на github . Он основан на стандартном приложении mvc 3 с поддержкой Spring.Net Mvc3 . Соответствующие файлы:

Ссылки

3 голосов
/ 02 февраля 2012

Ваш подход может быть правильным, однако я не вижу, как вы извлекаете экземпляры вашего прокси MyController класса. Как вы указали в комментарии, вы не используете spring для получения экземпляров MyController. В основном у Spring нет шансов перехватить этот вызов, и поэтому он не может создать динамический прокси-сервер (например, экземпляр с завернутыми советами вокруг исходного экземпляра).

Я настоятельно рекомендую вам взглянуть на примеры, которые делают то же, что вы пытаетесь выполнить , но используете уже встроенный совет ведения журнала .

Также обязательно включите ведение журнала отладки весной и внимательно прочитайте журнал. Spring записывает в журнал, какие типы проксируются, и если советы обернуты вокруг.

Что касается вашей проблемы, вот дикая догадка: В настоящее время я не уверен, но вы можете пропустить сборку Атрибута в вашем объявлении: <property name="AttributeTypes" value="MyApp.Aspects.LoggingAttribute"/> возможно, переписав его в: <property name="AttributeTypes" value="MyApp.Aspects.LoggingAttribute, MyApp"/> помогает весне найти атрибут.

...