Spring.Net学习系列一: 统一异常处理
在实际项目中,日志处理是一项常见的功能,如何统一处理异常?
一般的做法是会写个LogProvider类或ILogProvider接口,然后把错误信息通过这个provider写入文件或者数据库等等。
如:
try
{
helloWorld.Show();
}
catch(Exception ex)
{
LogProvider.Write(ex.StackTrace);
MessageBox.show("发生错误");
}
这样会到处充斥着LogProvider.Write(ex.StackTrace);
这样类似的代码,是不是闻到了坏味道?
是的,我们需要想办法放在一个统一的地方,一是代码美观,二是也便于维护。
这个时候我们的Spring.net出马了。利用Spring的AOP,,通过代理,我们可以很方便的统一处理这些异常信息。
当然,异常的记录一般是通过日志模块来处理。所以我们先实现一个日志模块,这里用大名鼎鼎的Log4Net,
稍作封装后,代码如下:
代码
1 using System;
2 using System.Collections.Generic;
3 using System.Text;
4
5 namespace Log
6 {
7 public class Log
8 {
9 private static Log instance;
10 private static readonly log4net.ILog log = log4net.LogManager.GetLogger("AppLog");
11 private static object obj=new object ();
12 private Log()
13 {
14
15 }
16 /// <summary>
17 /// 获取Log单例
18 /// </summary>
19 /// <returns></returns>
20 public static Log GetInstance()
21 {
22 if (instance == null)
23 {
24 lock (obj)
25 {
26 instance = new Log();
27 log4net.Config.XmlConfigurator.Configure();
28 }
29 }
30 return instance;
31 }
32
33 public void Debug(object o)
34 {
35 if (log.IsDebugEnabled)
36 {
37 if (o is Exception) log.Debug("Debug", o as Exception);
38 else log.Debug(o.ToString());
39
40 }
41 }
42
43 public void Error(object o)
44 {
45 if (log.IsErrorEnabled)
46 {
47 if (o is Exception) log.Error("Error", o as Exception);
48 else log.Error(o.ToString());
49 }
50 }
51
52 public void Warn(object o)
53 {
54 if (log.IsWarnEnabled)
55 {
56 if (o is Exception) log.Warn("Warn", o as Exception);
57 else log.Warn(o.ToString());
58 }
59 }
60
61 public void Info(object o)
62 {
63 if (log.IsInfoEnabled)
64 {
65 if (o is Exception) log.Info("Info", o as Exception);
66 else log.Info(o.ToString());
67 }
68 }
69
70 public void Fatal(object o)
71 {
72 if (log.IsFatalEnabled)
73 {
74 if (o is Exception) log.Fatal("Fatal", o as Exception);
75 else log.Fatal(o.ToString());
76 }
77 }
78 }
79 }
80
接下来我们通过 Spring.Net 的 AOP 特性实现异常的统一处理,如果我们需要在异常发生时做一些操作的话我们就必须实现 Spring.Aop.IThrowsAdvice,该接口没有任何实现方法,是一个空接口,它仅仅做为一个标记接口而存在,但实现了 IThrowsAdvice 接口的类必须定义至少一个 AfterThrowing 方法,方法的签名如下:
AfterThrowing([MethodInfo method, Object[] args, Object target], Exception subclass);
其中中括号括起来的前三个参数是可选的,返回值可以是任意数据类型。Spring.Aop.Framework.Adapter.ThrowsAdviceInterceptor 类实现对实现了 Spring.Aop.IThrowsAdvice 派生类中的方法依赖注入,其中的 ThrowsAdviceInterceptor() 方法检查 Spring.Aop.IThrowsAdvice 的派生类是否定义了至少一个异常处理方法,如果没有则抛出 ArgumentException 异常,MapAllExceptionHandlingMethods() 方法则在定义好的重载方法中查找出异常类型与最后一个参数所定义的类型中最接近的方法,而且我们不应该在其中实现了两个相同异常类型的方法,即使他们的参数数目不同,否则也将抛出 ArgumentException 异常。
代码
1 using System;
2 using System.Collections.Generic;
3 using System.Text;
4 using Spring.Aop;
5 using System.Reflection;
6 namespace Log
7 {
8 public class ExceptionThrowAdvice : IThrowsAdvice
9 {
10 private Log logInstance;
11
12 public ExceptionThrowAdvice()
13 {
14 logInstance = Log.GetInstance();
15 }
16
17 public void AfterThrowing(MethodInfo method, Object[] args, Object target, Exception exception)
18 {
19 logInstance.Error(exception);
20 }
21 }
22 }
23
接下来我们开始测试效果
首先定义一个接口以及实现类
如果使用spring.net+Nhibernate,这里就是Service和IService了(呵呵比较熟悉了吧)
using System;
using System.Collections.Generic;
using System.Text;
namespace LogTest
{
public inte易做图ce IHelloWorld
{
void Show();
}
}
代码
using System;
using System.Collections.Generic;
using System.Text;
namespace LogTest
{
public class HelloWorld:IHelloWorld
{
#region IHelloWorld 成员
public void Show()
{
throw new Exception("发生异常");
}
#endregion
}
}
然后就是配置文件了
objects.xml
代码
<?xml version="1.0" encoding="utf-8" ?>
<objects xmlns="http://www.springframework.net" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.net
http://www.springframework.net/xsd/spring-objects.xsd">
<object id="ExceptionThrowAdvice" type="Log.ExceptionThrowAdvice, Log" />
<object id="HelloWorld" type="LogTest.HelloWorld, LogTest" />
<object id="HelloWorldProxy" type="Spring.Aop.Framework.ProxyFactoryObject, Spring.Aop" >
<property name="ProxyInte易做图ces">
<list>
<value>LogTest.IHelloWorld,LogTest</value>
</list>
</property>
<property name="Target">
<ref object="HelloWorld" />
</property>
<property name="InterceptorNames">
<list>
<value>ExceptionThrowAdvice</value>
</list>
</property>
</object>
</objects>
app.config
代码
<?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>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net" />
</configSections>
<!--spring配置-->
<spring>
<context>
<resource uri="~/objects.xml"/>
</context>
</spring>
<!-- Log输出定义 -->
<log4net>
<appender name="LogFileAppender" type="log4net.Appender.FileAppender" >
<param name="File" value="log.text" />
<param name="datePattern" value="MM-dd HH:mm" />
<param name="AppendToFile" value="true" />
<layout type="log4net.Layout.PatternLayout">
<param name="ConversionPattern" value="%d [%t] %-5p %c
补充:Web开发 , ASP.Net ,