• TinyFrame再续篇:整合Spring AOP实现日志拦截


    上一篇中主要讲解了如何使用Spring IOC实现依赖注入的。但是操作的时候,有个很明显的问题没有解决,就是日志记录问题。如果手动添加,上百个上千个操作,每个操作都要写一遍WriteLog方法,工作量的巨大是可想而知的,更别说还有用户验证这块了。所以说,解决这种问题的方法最好是进行类的横切,OK,让我们进入正题吧。

    首先,在解决方案中新建一个名称为BookStore.AOP的类库项目,然后向其中添加IAdvice并继承自IMethodInterceptor接口和IDisposable接口。

    然后定义三个方法:

    void Initializement();

    void BeforeCall(IMethodInvocation invocation);

    void AfterCall(IMethodInvocation invocation);

    具体代码如下:

       1:  using System;
       2:  using AopAlliance.Intercept;
       3:   
       4:  namespace BookStore.AOP
       5:  {
       6:      public interface IAdvice : IMethodInterceptor, IDisposable
       7:      {
       8:          void Initializement();
       9:          void BeforeCall(IMethodInvocation invocation);
      10:          void AfterCall(IMethodInvocation invocation);
      11:      }
      12:  }

    其中Initializement方法主要提供初始化行文;BeforeCall方法主要是在函数执行前触发;AfterCall方法主要是在函数执行后触发。

    建立好这个接口之后,新建一个LogAdvice类,继承自刚刚建立的IAdvice接口,并添加如下代码:

       1:  using System;
       2:   
       3:  namespace BookStore.AOP
       4:  {
       5:      /*
       6:       请在需要消费AOP的地方添加对BookStore.AOP的引用,否则会出现错误。
       7:       */
       8:      public class LogAdvice:IAdvice
       9:      {
      10:          public LogAdvice()
      11:          {
      12:              Initializement();
      13:          }
      14:   
      15:          private log4net.ILog log;
      16:   
      17:          public void Initializement()
      18:          {
      19:              log4net.Config.XmlConfigurator.Configure();
      20:              log = log4net.LogManager.GetLogger(typeof(LogAdvice));
      21:          }
      22:   
      23:          public void BeforeCall(AopAlliance.Intercept.IMethodInvocation invocation)
      24:          {
      25:              log.Info(string.Format("调用函数开始:{0}", invocation.Method.Name));
      26:          }
      27:   
      28:          public void AfterCall(AopAlliance.Intercept.IMethodInvocation invocation)
      29:          {
      30:              log.Info(string.Format("调用函数结束:{0}", invocation.Method.Name));
      31:          }
      32:   
      33:          public object Invoke(AopAlliance.Intercept.IMethodInvocation invocation)
      34:          {
      35:              try
      36:              {
      37:                  BeforeCall(invocation);
      38:                  object resultObj = invocation.Proceed();
      39:                  AfterCall(invocation);
      40:                  return resultObj;
      41:              }
      42:              catch (Exception ex)
      43:              {
      44:                  log.Error(string.Format("调用函数错误:{0},{1},{2}", invocation.Method.Name, ex.Message, ex.StackTrace));
      45:                  return null;
      46:              }
      47:          }
      48:   
      49:          public void Dispose()
      50:          {
      51:              
      52:          }
      53:      }
      54:  }

    由于这里的日志记录,我采用了Log4net来进行配置,所以不懂的同学,可以参考我之前的文章Log4Net使用方法小记来进行。

    需要说明一点的是,在BeforeCall函数,AfterCall函数,Invoke函数中,我们得到的传入参数都是AopAlliance.Intercept.IMethodInvocation,通过这个参数,我们可以拦截用户当前请求的是什么函数,什么类型等等,非常方便。需要特别注意的是,在Invoke方法中,程序调用invocation.Proceed来拦截函数的执行,这也就是所谓的方法横切操作。

    写到这里,我们的编码工作算是完成了,下面来开始配置AOP横切。

    打开BookStore.RestService项目,双击Web.config配置文件,新添加如下的节点段落,名称分别为BookRepositoryAOP以及LogTraceAroundAdvice:

       1:  <!--Spring Config Node-->
       2:    <spring>
       3:      <context>
       4:        <resource uri="config://spring/objects"/>
       5:      </context>
       6:      <objects xmlns="http://www.springframework.net">
       7:        <!--without aop-->
       8:        <object name="BookRepository" type="BookStore.Data.BookRepository, BookStore.Data" />
       9:        
      10:        <!--with aop-->
      11:        <object name="BookRepositoryAOP" type="Spring.Aop.Framework.ProxyFactoryObject" >
      12:          <property name="Target">
      13:            <object type="BookStore.Data.BookRepository, BookStore.Data" />
      14:          </property>
      15:          <property name="InterceptorNames">
      16:            <list>
      17:              <value>LogTraceAroundAdvice</value>
      18:            </list>
      19:          </property>
      20:        </object>
      21:        <!--Advices-->
      22:        <object id="LogTraceAroundAdvice" type="BookStore.AOP.LogAdvice, BookStore.AOP"></object>
      23:      </objects>
      24:    </spring>

    其中名称为BookRepositoryAOP的节点表明当前采用AOP方式进行,横切的目标是BookStore.Data.BookRepository;横切的处理是BookStore.AOP.LogAdvice。配置好后,一定不要忘记添加对BookStore.AOP项目的引用。

    这之后,打开BookService类,修改构造初始化为刚刚配置的节点:

       1:   public BookService()
       2:              : base()
       3:          {
       4:              bookRepository = (IBookRepository)applicationContext["BookRepositoryAOP"];
       5:          }

    然后执行,我们就可以看到拦截的日志消息了,如果执行的时候,出现错误,还能够将错误信息捕捉,是不是感觉有了AOP,腰不酸了,腿不痛了的感觉呢?

    QQ截图20140307150338

    这节就到这里了,下节主要讲解用户验证这块,也是利用横切来进行。

    这里允许我白话一下:接口这东西在小项目中根本用不到,但是在大项目中,是必不可少的。IOC,AOP全靠它了。并且模块与模块之间交互,利用接口来规范,大大降低了耦合度,真好啊。

  • 相关阅读:
    Codeforces Round #700 (Div. 2)
    2020-2021 ACM-ICPC Brazil Subregional Programming Contest
    Codeforces Round #699 (Div. 2)
    2021牛客寒假算法基础集训营3
    2021牛客寒假算法基础集训营1
    Educational Codeforces Round 103 (Rated for Div. 2)
    Codeforces Round #697 (Div. 3)
    Codeforces Round #696 (Div. 2)
    2017 ECNA Regional Contest
    spring的aop详解
  • 原文地址:https://www.cnblogs.com/scy251147/p/3586459.html
Copyright © 2020-2023  润新知