经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » 设计模式 » 查看文章
错误日志之观察者模式
来源:cnblogs  作者:MedlarCanFly  时间:2019/9/10 10:57:44  对本文有异议

星期一

情景

早晨,项目组长来到小明身边,“有人反映咱们的项目有Bug” “什么Bug?” “不知道,你添加一个日志模块自己看记录去。” ”...“

分析

在MVC全局过滤器中自己添加有异常过滤器。

Global.asax

  1. 1 public class MvcApplication : System.Web.HttpApplication
  2. 2 {
  3. 3 protected void Application_Start()
  4. 4 {
  5. 5 AreaRegistration.RegisterAllAreas();
  6. 6 //注册全局过滤器
  7. 7 FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
  8. 8 RouteConfig.RegisterRoutes(RouteTable.Routes);
  9. 9 BundleConfig.RegisterBundles(BundleTable.Bundles);
  10. 10 }
  11. 11 }
View Code

 

 FilterConfig.cs

  1. 1 public class FilterConfig
  2. 2 {
  3. 3 public static void RegisterGlobalFilters(GlobalFilterCollection filters)
  4. 4 {
  5. 5 //向全局过滤器中添加异常过滤器
  6. 6 //只要你的项目出现了异常,就会执行过滤器里的OnException方法
  7. 7 filters.Add(new HandleErrorAttribute());
  8. 8 }
  9. 9 }
View Code

 

开工

整理思路:发生错误时要执行自己需要的代码,只需要继承IExceptionFilter,重写OnException方法,然后把自己的过滤器注册到全局即可。

创建过滤器,MyExceptionFilter类

  1. 1 //因为微软已经提供了一个HandleErrorAttribute类(它其实也是继承了IExceptionFilter),所以我们只需继承它即可
  2. 2 public class MyExceptionFilter: HandleErrorAttribute
  3. 3 {
  4. 4 //重写OnException方法
  5. 5 public override void OnException(ExceptionContext filterContext)
  6. 6 {
  7. 7 base.OnException(filterContext);
  8. 8
  9. 9 //把错误写到日志文件里面去
  10. 10 //思考:如果同时来了多个错误,一起向文件中写内容,就会发生同时访问同一个文件问题。你会怎么解决?
  11. 11 //提示:锁、队列
  12. 12
  13. 13 //LogHelper类用来把错误写到日志里面去
  14. 14 LogHelper.Write(filterContext.Exception.ToString());
  15. 15
  16. 16 }
  17. 17 }

 

 

LogHelper类,用来把错误写到日志里面去

  1. 1 public class LogHelper
  2. 2 {
  3. 3 //添加一个静态的异常信息队列,只要出现异常就写到队列中。
  4. 4 public static Queue<string> ExceptionStringQueue = new Queue<string>();
  5. 5
  6. 6 //第一次用到该类型时会执行静态构造函数,只被执行一次
  7. 7 static LogHelper()
  8. 8 {
  9. 9 //创建一个线程池,将方法排入队列以便执行
  10. 10 ThreadPool.QueueUserWorkItem(o => {
  11. 11 while (true)
  12. 12 {
  13. 13 lock (ExceptionStringQueue)
  14. 14 {
  15. 15 //如果有错误信息写入日志
  16. 16 if (ExceptionStringQueue.Count > 0)
  17. 17 {
  18. 18 string exceptionString = ExceptionStringQueue.Dequeue();
  19. 19 //把错误信息写到日志文件中
  20. 20 using (System.IO.StreamWriter file = new System.IO.StreamWriter(@"C:\Log.txt", true))
  21. 21 {
  22. 22 file.WriteLine(exceptionString);// 直接追加文件末尾,换行
  23. 23 }
  24. 24 }
  25. 25 else
  26. 26 {
  27. 27 Thread.Sleep(1000);
  28. 28 }
  29. 29
  30. 30 }
  31. 31 }
  32. 32 });
  33. 33 }
  34. 34
  35. 35
  36. 36 //给外部提供方法,将错误信息写入队列
  37. 37 public static void Write(string exceptionString)
  38. 38 {
  39. 39 lock (ExceptionStringQueue)
  40. 40 {
  41. 41 //将错误信息添加到队列
  42. 42 ExceptionStringQueue.Enqueue(exceptionString);
  43. 43 }
  44. 44 }
  45. 45 }
View Code

 

把自己的过滤器注册到全局

  1. 1 public class FilterConfig
  2. 2 {
  3. 3 public static void RegisterGlobalFilters(GlobalFilterCollection filters)
  4. 4 {
  5. 5 //向全局过滤器中添加异常过滤器
  6. 6 //只要你的项目出现了异常,就会执行过滤器里的OnException方法
  7. 7 //filters.Add(new HandleErrorAttribute());
  8. 8 //把自己的过滤器注册到全局
  9. 9 filters.Add(new MyExceptionFilter());
  10. 10 }
  11. 11 }
View Code

 

自定义错误测试

  1. 1 throw new Exception("自定义错误");
View Code

 

 OK,大功告成,以后就可以根据日志来找错误了。 

星期二

情景

早晨,项目组长又来到小明身边,”昨天我用了你的错误日志功能,还不错,但是你将日志写在文件中整理不是太方便,还存在共享冲突问题,你改下写到数据库中“ ”...“

分析

查看昨天写的代码

发现此处是一个变化点,有可能写到文件中,有可能写到数据库中,有可能......

不就是写到不同的地方么,简单,多态就能搞定了。

开工

依赖于抽象,而不依赖于具体

创建IWriteLog接口

  1. 1 public interface IWriteLog
  2. 2 {
  3. 3 //把错误信息写到相应的地方
  4. 4 void WriteLog(string exceptionString);
  5. 5 }
View Code

创建WriteLogToText类实现接口,用来写入文本

  1. 1 public class WriteLogToText : IWriteLog
  2. 2 {
  3. 3 public void WriteLog(string exceptionString)
  4. 4 {
  5. 5 //将错误信息写入文本
  6. 6 }
  7. 7 }
View Code

 创建WriteLogToSqlServer类实现接口,用来写入数据库

  1. 1 public class WriteLogToSqlServer : IWriteLog
  2. 2 {
  3. 3 public void WriteLog(string exceptionString)
  4. 4 {
  5. 5 //将错误信息写入数据库
  6. 6 }
  7. 7 }
View Code

 

对变化点进行修改

  1. 1 string exceptionString = ExceptionStringQueue.Dequeue();
  2. 2 //依赖接口
  3. 3 IWriteLog writeLog = new WriteLogToSqlServer();
  4. 4 //IWriteLog writeLog = new WriteLogToText();
  5. 5 //把错误信息写到相应的地方
  6. 6 writeLog.WriteLog(exceptionString);

 OK,大功告成,又可以去美滋滋了...

星期三

情景

早晨,项目组长再一次来到小明身边,”经过我的思考,我觉得把错误信息同时写到文本和数据库中比较好“ ”为什么?“ “需求” “...”

分析

错误信息有可能要写到不同的地方,而且不知道有多少地方,说不定明天又加了一个Redis、后天再加一个....

这时候我们可以考虑创建一个集合来保存都需要写到那些地方去。(这里插一句:设计模式只是一种思想,实现方式肯定是不唯一的,但是思想是精髓,不能说这个代码是这个模式,换一种方式实现就不是这个模式了。

然后依次写入即可。

开工

对LogHelper进行修改

  1. 1 public class LogHelper
  2. 2 {
  3. 3 //添加一个静态的异常信息队列,只要出现异常就写到队列中。
  4. 4 public static Queue<string> ExceptionStringQueue = new Queue<string>();
  5. 5
  6. 6 //定义一个集合来存放所有的 观察者,
  7. 7 public static IList<IWriteLog> writeLogList = new List<IWriteLog>();
  8. 8
  9. 9 //第一次用到该类型时会执行静态构造函数,只被执行一次
  10. 10 static LogHelper() {
  11. 11
  12. 12 //观察(订阅)
  13. 13 writeLogList.Add(new WriteLogToSqlServer());
  14. 14 writeLogList.Add(new WriteLogToText());
  15. 15
  16. 16 //创建一个线程池,将方法排入队列以便执行
  17. 17 ThreadPool.QueueUserWorkItem(o=> {
  18. 18 while (true)
  19. 19 {
  20. 20 lock (ExceptionStringQueue)
  21. 21 {
  22. 22 //如果有错误信息写入日志
  23. 23 if (ExceptionStringQueue.Count > 0)
  24. 24 {
  25. 25 string exceptionString = ExceptionStringQueue.Dequeue();
  26. 26 //发布
  27. 27 foreach (var writeLog in writeLogList)
  28. 28 {
  29. 29 writeLog.WriteLog(exceptionString);
  30. 30 }
  31. 31 }
  32. 32 else
  33. 33 {
  34. 34 Thread.Sleep(1000);
  35. 35 }
  36. 36 }
  37. 37 }
  38. 38
  39. 39 });
  40. 40 }
  41. 41
  42. 42
  43. 43 //给外部提供方法,将错误信息写入队列
  44. 44 public static void Write(string exceptionString) {
  45. 45 lock (ExceptionStringQueue)
  46. 46 {
  47. 47 //将错误信息添加到队列
  48. 48 ExceptionStringQueue.Enqueue(exceptionString);
  49. 49 }
  50. 50 }
  51. 51 }

后期如果还需要写入其它地方或者去掉一个的话,只需要Add一个或者删除一行即可。当然,现在的代码还有很多可优化的地方,比如把通知者(LogHelper)进行抽象,还可以通过配置文件加反射再次解耦。这里就不做过多介绍了。因为已经星期四了...

星期四

采用Log4Net

总结

观察者模式又叫发布-订阅模式,定义了一种一对多的依赖关系,让多个观察者同时监听同一个对象。当对象状态发生改变时,通知所订阅的观察者。

什么时候使用?

当一个对象改变同时需要改变其他对象,并且还不知道要改变多少对象。这时应该考虑观察者模式。

 

原文链接:http://www.cnblogs.com/MedlarCanFly/p/11480095.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号