在自动代理/代理工厂对象上处理异常

时间:2011-11-19 18:47:14

标签: exception-handling spring.net aop

我开始学习Spring.NET框架,我对代理行为,自动代理和异常处理非常困惑。

例如我定义了简单的业务对象,从这个对象中我将抛出自定义异常。

namespace Aspect.Managers
{
    public interface IDbCustomerManager
    {
        Customer GetCustomerById(long id);
    }

    public class DbCustomerManager:IDbCustomerManager
    {

        public Customer GetCustomerById(long id)
        {
            throw new DbException(string.Format("Problem load customer with Id: {0}",id));
        }

    }
}

其次我定义了处理异常的建议。

public class LogExThrowsAdvice:IThrowsAdvice
{
    public void AfterThrowing(MethodInfo method, Object[] args,
            Object target, DbException exception)
    {
        Console.WriteLine(exception.Message);

    }
}

最后,我加入了代理业务对象和建议。

在app.confing中

建议:

  <object id="theLogExThrowsAdvice"
          type="Aspect.LogExThrowsAdvice, Log4NetInSpringNet"/>

自动代理

  <object id="theProxyCreator"
          type="Spring.Aop.Framework.AutoProxy.TypeNameAutoProxyCreator, Spring.Aop">
    <property name="TypeNames" value="Aspect.Managers.DbCustomerManager*"/>
    <property name="InterceptorNames">
      <list>
        <value>theLogExThrowsAdvice</value>
      </list>
    </property>
  </object>

测试一下:

            var springContext = ContextRegistry.GetContext();
            var dbMgr = (IDbCustomerManager)springContext["theDbCustomerManager"];
            dbMgr.GetCustomerById(1);

异常被抛出,来自LogExThrowsAdvice的AfterThrowing方法未调用。

我尝试更改类型为BeforeAdvice的建议类型。

 public class DbAccessAdvice:IMethodBeforeAdvice
{
    #region Implementation of IMethodBeforeAdvice

    public void Before(MethodInfo method, object[] args, object target)
    {
        Console.WriteLine("You try access to DB");
    }

    #endregion
}

并在app.config中:

  <object id="theDbAccessAdvice"
          type="Aspect.DbAccessAdvice, Log4NetInSpringNet"/>


  <object id="theProxyCreator"
          type="Spring.Aop.Framework.AutoProxy.TypeNameAutoProxyCreator, Spring.Aop">
    <property name="TypeNames" value="Aspect.Managers.DbCustomerManager*"/>
    <property name="InterceptorNames">
      <list>
        <value>theDbAccessAdvice</value>
        <value>theLogExThrowsAdvice</value>
      </list>
    </property>
  </object>

BeforeAdvice是火,但是ThrowsAdvice没有。为什么呢?

我尝试更改代理对象工厂的自动代理,并尝试代理接口IDbCustomerManager。

  <object id="theProxy"
          type="Spring.Aop.Framework.ProxyFactoryObject, Spring.Aop">
    <property name="ProxyInterfaces" value="Aspect.Managers.IDbCustomerManager"/>
    <property name="Target">
      <object type="Aspect.Managers.DbCustomerManager">
      </object>
    </property>
    <property name="InterceptorNames">
      <list>
        <value>theDbAccessAdvice</value>
        <value>theLogAdvice</value>
      </list>
    </property>
  </object>
  var springContext = ContextRegistry.GetContext();
  var dbMgr = (IDbCustomerManager)springContext["theProxy"];
  dbMgr.GetCustomerById(1);

在提出建议之前,建议不是吗?为什么?只抛出异常。

对我而言,它是如何真正起作用的。

我尝试使用Advisors而不是建议:

  <!--Advisor-->
  <object id="theDbAccessAdvisor"
          type="Spring.Aop.Support.RegularExpressionMethodPointcutAdvisor, Spring.Aop">
    <property name="Pattern" value="Aspect*"/>
    <property name="Advice"  ref="theDbAccessAdvice"/>
  </object>

  <object id="theLogAdvisor"
    type="Spring.Aop.Support.RegularExpressionMethodPointcutAdvisor, Spring.Aop">
    <property name="Pattern" value="Aspect*"/>
    <property name="Advice"  ref="theLogAdvice"/>
  </object>

但是建议被解雇之前的结果相同,但不会抛出建议。

我尝试过使用Spring.NET的ExceptionHandleAdvice方面,抛出相同的异常,但建议没有。

 <object id="exAdvice"
          type="Spring.Aspects.Exceptions.ExceptionHandlerAdvice, Spring.Aop">
    <property name="ExceptionHandlers">
      <list>
        <value>on exception name DbException swallow</value>
      </list>
    </property>
  </object>

这个项目对我来说很神奇我在这里上传了所有VS项目:

http://hotfile.com/dl/135485464/93558e0/Log4Net.7z.html

这是例外的stackTrace:

  

在Aspect.Managers.DbCustomerManager.GetCustomerById(Int64 id)中   E:\ C#   项目\研究\ SPRING.NET \ Study.Spring.Net \ \方面记录\ log4net的\经理\ DbCustomerManager.cs:行   20点到   Spring.Reflection.Dynamic.SafeMethod.Invoke(Object中的_dynamic_Aspect.Managers.DbCustomerManager.GetCustomerById(Object,Object [])   target,Object [] arguments)at   Spring.Aop.Framework.DynamicMethodInvocation.InvokeJoinpoint()at   Spring.Aop.Framework.AbstractMethodInvocation.Proceed()at   Spring.Aspects.Exceptions.ExceptionHandlerAdvice.Invoke(IMethodInvocation   调用)

此外,如果我尝试捕获这样的异常:

        try
        {
            var springContext = ContextRegistry.GetContext();
            var dbMgr = (IDbCustomerManager)springContext["theDbCustomerManager"];
            dbMgr.GetCustomerById(1);
        }
        catch (Exception ex)
        {

            Console.WriteLine("{0}\n{1}", ex.GetType(), ex.Message);
        }

不可能..系统显示消息是未处理的异常....

2 个答案:

答案 0 :(得分:1)

我测试了你的包裹。一切正常(我正在使用v1.3.2)。 AfterThrows建议捕获异常(使用断点)但不会被忽略。 这是我的配置:

public void AfterThrowing(MethodInfo method, Object[] args,
    Object target, DbException exception)
{
    Console.WriteLine(exception.Message);

}
<!--DAO-->
<object id="theCustomerDao"
        type="Aspect.Dao.CustomerDao"/>

<!--Business object-->
<object id="theDbCustomerManager"
        type="Aspect.Managers.DbCustomerManager">
  <!--<property name="CustomerDao" ref="theCustomerDao"/>-->
</object>


<!--Advices-->     
<object id="theLogAdvice"
        type="Aspect.LogExThrowsAdvice, Log4NetInSpringNet"/>

<!--Proxy creator-->
<object type="Spring.Aop.Framework.AutoProxy.TypeNameAutoProxyCreator, Spring.Aop">
  <property name="TypeNames" value="Aspect.Managers.DbCustomerManager*"/>
  <property name="InterceptorNames">
    <list>
      <value>theLogAdvice</value>
    </list>
  </property>
</object>

答案 1 :(得分:1)

如果你把你的代码与bbaia的配置结合起来,那么我认为你已经到了一半了。

从您的问题和评论中,我了解您想要吞下DbException。 请注意,一般来说,您永远不会希望您的记录器吞下异常,但为了问题,请假设您这样做 - 但我保证您永远不会在生产环境中执行此操作: - )

我建议您稍微调整一下LogExThrowsAdvice

public class LogExThrowsAdvice : Spring.Aspects.Exceptions.ExceptionHandlerAdvice, IThrowsAdvice
{
    public void AfterThrowing(MethodInfo method, Object[] args,
        Object target, Exception exception)
    {
        Console.WriteLine(exception.Message);

    }
}

继承ExceptionHandlerAdvice允许您指定how to handle thrown exceptions,例如吞下它。 然后拿bbaia的配置并为它添加一个事件处理程序:

<object id="theLogAdvice"
        type="Aspect.LogExThrowsAdvice, Log4NetInSpringNet">
  <property name="exceptionHandlers">
    <list>
      <value>on exception name DbException swallow</value>
    </list>
  </property>
</object>

现在吞下了所有DbException

关于你在Visual Studio中如何引发的问题:你的VS是否可以设置为“中断抛出的异常”?转到调试 - &gt;例外和_un_check公共语言运行时异常的Thrown复选框。

请注意,如果您选中此选项,则在引发异常时仍可继续:程序不会崩溃,因为会处理异常。