Пример ведения журнала Spring.net с использованием aop - PullRequest
1 голос
/ 06 ноября 2011

Я изучаю Spring.Net и пробую что-то простое, которое не работает. Я хочу регистрировать любые вызовы методов, украшенные LogCall

namespace WpfApplication1
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            Test();
            InitializeComponent();
        }

        [LogCall]
        public void Test()
        {
        }
    }

    public class LogCallInterceptor : IMethodBeforeAdvice
    {
        public void Before(MethodInfo method, object[] args, object target)
        {
            Debug.Write(method.Name);
        }
    }

    [Serializable]
    [AttributeUsage(AttributeTargets.Method)]
    public class LogCallAttribute : Attribute
    {
    }
}

А вот и App.config

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <spring>
    <objects xmlns="http://www.springframework.net">
      <object id="TestLogAdvice" type="Spring.Aop.Support.AttributeMatchMethodPointcutAdvisor, Spring.Aop">
        <property name="advice">
          <object type="WpfApplication1.LogCallInterceptor, WpfApplication1" />
        </property>
        <property name="attribute" value="WpfApplication1.LogCallAttribute, WpfApplication1" />
      </object>
    </objects>
  </spring>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="Spring.Core" publicKeyToken="65e474d141e25e07" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-1.3.2.40943" newVersion="1.3.2.40943" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="Spring.Aop" publicKeyToken="65e474d141e25e07" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-1.3.2.40943" newVersion="1.3.2.40943" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
</configuration>

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

Основываясь на первом ответе, я переделал свой пример. До сих пор не работает? Я греюсь?

namespace WpfApplication1
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            var someClass = new SomeClass();
            someClass.Test();
            InitializeComponent();
        }
    }

    public class SomeClass
    {
        [LogCall]
        public void Test()
        {
        }
    }

    public class LogCallInterceptor : IMethodBeforeAdvice
    {
        public void Before(MethodInfo method, object[] args, object target)
        {
            Debug.Write(method.Name);
        }
    }

    [Serializable]
    [AttributeUsage(AttributeTargets.Method)]
    public class LogCallAttribute : Attribute
    {
    }
}

И новый app.config

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <spring>
    <objects xmlns="http://www.springframework.net">
      <object id="TestLogAdvice" type="Spring.Aop.Support.AttributeMatchMethodPointcutAdvisor, Spring.Aop">
        <property name="advice">
          <object type="WpfApplication1.LogCallInterceptor, WpfApplication1" />
        </property>
        <property name="attribute" value="WpfApplication1.LogCallAttribute, WpfApplication1" />
      </object>
    </objects>
    <object id="mySomeClass" type="Spring.Aop.Framework.ProxyFactoryObject">
      <property name="target">
        <object id="mySomeClassTarget" type="WpfApplication1.SomeClass"/>
      </property>
      <property name="interceptorNames">
        <list>
          <value>TestLogAdvice</value>
        </list>
      </property>
    </object>  
  </spring>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="Spring.Core" publicKeyToken="65e474d141e25e07" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-1.3.2.40943" newVersion="1.3.2.40943" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="Spring.Aop" publicKeyToken="65e474d141e25e07" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-1.3.2.40943" newVersion="1.3.2.40943" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
</configuration>

1 Ответ

3 голосов
/ 06 ноября 2011

Вы используете Spring AOP для настройки ведения журнала, и это правильный подход.Есть несколько вещей, которые вы должны учитывать:

Spring AOP использует динамический прокси для украшения класса советами (регистрации).Этот прокси перехватывает вызовы вашего объекта и применяет рекомендации по ведению журнала.В вашем классе вы вызываете метод Test из внутри самого класса.Таким образом, динамический прокси-сервер никогда не сможет перехватить вызов, и регистрация не будет осуществляться.

Из вашей конфигурации я прочитал, что вы определяете, какой совет должен выполняться (ваш LogCallInterceptor) и где (методы, соответствующие вашему атрибуту), но я не вижу, где вы определяете свою фабрику прокси.Spring должен создать прокси, и вы должны указать, где это сделать.

Быстрый запуск aop - хорошее место, чтобы узнать, как это сделать.Фактически, одним из первых примеров является пример регистрации, который очень применим к вашему вопросу.Я предполагаю, что после прочтения первой части краткого руководства (глава 38.2.1.) Вы узнаете, что нужно сделать, чтобы это заработало.

Spring AOP - это мощная техника, но она может быть немноготрудно освоить сначала.Вы уже в пути.

Изменить 1

Я вижу, вы обновили свой вопрос.Думаю, вы почти у цели.

Теперь вы создаете SomeClass экземпляр непосредственно из кода.Таким образом, у Spring снова нет шансов создать свой прокси.Вы должны делегировать создание SomeClass контейнеру пружины:

public MainWindow()
{
  // normally speaking, we should not create the container here,
  // but that's another subject
  var ctx = ContexRegistry.GetContext(); // init spring container
  var someClass = (SomeClass) ctx["mySomeClass"];
  someClass.Test();
  InitializeComponent();
}

Таким образом, someClass будет удерживать прокси вместо цели.

После этого есть одинпроблема остается ( подсказка ).

Edit 2

Ваш метод Test должен быть виртуальным, иначе Spring не сможет создатьоснованный на наследовании прокси.(или ваш класс должен реализовать один или несколько интерфейсов).

Конфигурация с использованием автоматического прокси

В следующем файле app.config используется DefaultAdvisorAutoProxyCreator.Это позволит вам не создавать прокси-фабрику для каждого класса, к которому вы хотите применить ваш советник по ведению журнала.DefaultAdvisorAutoProxyCreator найдет все объекты с LogCallAttribute s и создаст для них прокси.

<?xml version="1.0" encoding="utf-8"?>

<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.springframework.net">

      <object id="TestLogAdvice" type="Spring.Aop.Support.AttributeMatchMethodPointcutAdvisor, Spring.Aop">
        <property name="advice">
          <object type="q8029460.LogCallInterceptor, q8029460" />
        </property>
        <property name="attribute" value="q8029460.LogCallAttribute, q8029460" />
      </object>

      <object id="ProxyCreator" type="Spring.Aop.Framework.AutoProxy.DefaultAdvisorAutoProxyCreator, Spring.Aop"/>

      <object id="mySomeClass" type="q8029460.MyClass, q8029460" />

    </objects>
  </spring>

</configuration>
...