• 使用AOP的方式监测方法执行耗时


      在一些对系统中,往往可能需要对一些核心业务做相应的监测。如:记录调用参数,返回值,方法执行耗时等等。如果直接在方法的前后加入代码,如下: 

     1  public int F(int a, string s)
     2         {
     3             var now = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff");
     4             var sw = Stopwatch.StartNew();
     5 
     6             int ret = 1;
     7 
     8             long second = sw.ElapsedMilliseconds;
     9             var end = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff");
    10             log.Write(now, end, second, a, s, ret);
    11         }

    这样有以下几点问题:

      1.将业务逻辑和方法执行监测混在一起。

      2.会有大量重复代码,哪怕你做了一层封装,也依然不够优雅。

    由于有了以上的问题,我们会思考,如果可以将方法的调用过程抽象出来,在方法开始调用和方法调用结束时,植入代码,这样就可以很好的解决我们的问题。

      .NET中,我们可以通过RealProxy来实现我们想要的功能。RealProxy(https://msdn.microsoft.com/zh-cn/library/vstudio/system.runtime.remoting.proxies.proxyattribute(v=vs.100).aspx)MSDN的定义。在Invoke方法中,可以拦截方法的执行,那么我们就可以在方法的执行前后做一些事情啦。

      那么怎么更优雅的应用在方法上呢,我们可以用ProxyAttribute使用Attribute的方式。可以在对象初始化的时候(new关键字)创建相应的代理类。具体代码如下:

        /// <summary>
        /// 标记要性能监测的类
        /// </summary>
        [AttributeUsage(AttributeTargets.Class)]
        public class MonitorServiceAttribute : ProxyAttribute
        {
            public override MarshalByRefObject CreateInstance(Type serverType)
            {
                var instance = base.CreateInstance(serverType);
                var proxy = new InjectProxy(serverType, instance).GetTransparentProxy();
                return proxy as MarshalByRefObject;
            }
    
        }

    InjectProxy代码如下:

     public override IMessage Invoke(IMessage msg)
            {
                var call = (IMethodCallMessage) msg;
                var ctr = call as IConstructionCallMessage;
    
                IMethodReturnMessage back;
                if (ctr != null)
                {
                    RealProxy defaultProxy = RemotingServices.GetRealProxy(_instance);
                    defaultProxy.InitializeServerObject(ctr);
                    back = EnterpriseServicesHelper.CreateConstructionReturnMessage(ctr,
                        (MarshalByRefObject) GetTransparentProxy());
                }
                else
                {
                    var now = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff");
                    var sw = Stopwatch.StartNew();
                    back = RemotingServices.ExecuteMessage(_instance, call);
                    long second = sw.ElapsedMilliseconds;
                    var attr = MethodAttributeCache.GetAttribute<MonitorMethodAttribute>(_instance.GetType().TypeHandle,
                        call.MethodBase);
    
                    if (attr != null)
                    {
                        attr.Value = second.ToString();
                        attr.ExecuteTime = now;
                        Queue.Enqueue(Mapper(attr));
                    }
                }
                return back;
            }

    我在这里只记录了方法执行耗时,可以从call里拿到参数,从back里获取到返回值。

    具体调用地方如下,注意类需要继承ContextBoundObject:

      internal class Program
        {
            private static void Main(string[] args)
            {
                var t = new Test();
                t.F(1,"aaa");
            }
        }
    
        [MonitorService]
        internal class Test : ContextBoundObject
        {
            [MonitorMethod("A")]
            public int F(int a,string s)
            {
                return 333;
            }
    
        }
  • 相关阅读:
    软件性能测试指标及其注意地方
    Oracle过程及函数的参数模式详解
    【转】Web Service单元测试工具实例介绍之SoapUI
    【转】如何读懂Oracle文档中的语法图
    浅谈session测试
    Cookie管理工具
    php 在linux 用file_exists() 函数判断 另外一台服务器映射过来的文件是否存在 总是返回false
    SecureCRT 设置字体跟颜色
    bootstrat 设置 select option 选项的值
    php 如何把中文写入json中 当json文件中还显示的是中文
  • 原文地址:https://www.cnblogs.com/LoveJerryZhang/p/4365261.html
Copyright © 2020-2023  润新知