处理自动代理/代理工厂对象上的异常
我开始学习 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
Advice:
<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);
在建议被解雇之前但抛出建议不是吗?为什么?仅抛出异常。
对我来说,它的真正运作方式很神奇。
我尝试使用顾问而不是建议:
<!--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\Aspects\Logging\Log4Net\Managers\DbCustomerManager.cs:行 20 点 _dynamic_Aspect.Managers.DbCustomerManager.GetCustomerById(Object , Object[] ) 在 Spring.Reflection.Dynamic.SafeMethod.Invoke(Object 目标,Object[] 参数)位于 Spring.Aop.Framework.DynamicMethodInitation.InvokeJoinpoint() 在 Spring.Aop.Framework.AbstractMethodInitation.Proceed() 在 Spring.Aspects.Exceptions.ExceptionHandlerAdvice.Invoke(IMethodInitation 调用)
另外,如果我尝试捕获类似这样的异常:
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);
}
这是不可能的..系统显示消息是未处理的异常....
I start learning Spring.NET framework and I am very confusing with behavior of proxy, auto-proxy and exception handling.
for example I defined simple business object and from this object I will throw custom exception.
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));
}
}
}
Second I defined Advice for handling with exception.
public class LogExThrowsAdvice:IThrowsAdvice
{
public void AfterThrowing(MethodInfo method, Object[] args,
Object target, DbException exception)
{
Console.WriteLine(exception.Message);
}
}
And last I join togheter business object and advice with proxy.
In app.confing
Advice:
<object id="theLogExThrowsAdvice"
type="Aspect.LogExThrowsAdvice, Log4NetInSpringNet"/>
Auto-Proxy
<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>
And test it:
var springContext = ContextRegistry.GetContext();
var dbMgr = (IDbCustomerManager)springContext["theDbCustomerManager"];
dbMgr.GetCustomerById(1);
Exception is throwed, method AfterThrowing from LogExThrowsAdvice is not calling.
I try changed type of advice for type 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
}
and in 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 is fire but ThrowsAdvice no. Why?
I tried change auto proxy for proxy object factory and tried proxying interfaces 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);
Before advice is fired but throws advice are not? why? Only exception is throwed.
For me is magic how it really work.
I tried used Advisors instead advices:
<!--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>
But same result before advice is fired but throws advice not.
I tried use also ExceptionHandleAdvice aspect from Spring.NET same exception is throwed but advice not.
<object id="exAdvice"
type="Spring.Aspects.Exceptions.ExceptionHandlerAdvice, Spring.Aop">
<property name="ExceptionHandlers">
<list>
<value>on exception name DbException swallow</value>
</list>
</property>
</object>
This project is for me magic I upload all VS project here:
http://hotfile.com/dl/135485464/93558e0/Log4Net.7z.html
Here is stackTrace of exception:
at Aspect.Managers.DbCustomerManager.GetCustomerById(Int64 id) in
E:\C#
PROJECTS\STUDY\SPRING.NET\Study.Spring.Net\Aspects\Logging\Log4Net\Managers\DbCustomerManager.cs:line
20 at
_dynamic_Aspect.Managers.DbCustomerManager.GetCustomerById(Object , Object[] ) at Spring.Reflection.Dynamic.SafeMethod.Invoke(Object
target, Object[] arguments) at
Spring.Aop.Framework.DynamicMethodInvocation.InvokeJoinpoint() at
Spring.Aop.Framework.AbstractMethodInvocation.Proceed() at
Spring.Aspects.Exceptions.ExceptionHandlerAdvice.Invoke(IMethodInvocation
invocation)
Also if I try catch exception something like this:
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);
}
It is not possible..system show message is unhandled exception....
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我测试了你的包裹。一切正常(我使用的是 v1.3.2)。
该异常由
AfterThrows
建议(使用断点)捕获,但不会被忽略。这是我的配置:
I tested your package. Everything works fine (I'm using v1.3.2).
The exception is caught by the
AfterThrows
advice (use a breakpoint) but not ignored.Here is my config:
如果你把你的代码和 bbaia 的配置结合起来,那么我想你已经成功了一半。
从您的问题和评论中,我了解到您想吞下
DbException
。请注意,一般来说,您永远不会希望您的记录器吞下异常,但为了问题的缘故,假设您这样做 - 但向我保证您永远不会在生产环境中这样做:-)
我建议您稍微调整您的 LogExThrowsAdvice 到:
继承自
ExceptionHandlerAdvice
允许您指定 如何处理抛出的异常,例如吞下它。然后获取 bbaia 的配置并向其中添加一个事件处理程序:
现在所有
DbException
都被吞掉了。关于您关于如何在 Visual Studio 中仍然抛出的问题:您的 VS 是否设置为“抛出异常时中断”?转到调试->异常并取消选中公共语言运行时异常的“抛出”复选框。
请注意,如果保持选中此项,则在引发异常时仍然可以继续:程序不会崩溃,因为异常已被处理。
If you take your code and combine it with bbaia's config, then you're halfway there I think.
From your question and comments, I understand that you want to swallow the
DbException
s.Note that generally speaking, you'd never want your logger swallow exceptions, but for the question's sake assume you do - but promise me you'll never do this in a production environment :-)
I suggest you slightly adjust your
LogExThrowsAdvice
to:Inheriting from
ExceptionHandlerAdvice
allows you to specify how to handle thrown exceptions, for instance swallow it.Then take bbaia's config and add an event handler to it:
Now all
DbException
s are swallowed.With respect to your question as to how this still throws in Visual Studio: could it be that your VS is set to "break on a thrown exception"? Go to Debug -> Exceptions and _un_check the Thrown checkbox for Common Language Runtime Exceptions.
Note that if you keep this checked, you can still continue when the exception is raised: the program will not crash, because the exception is handled.