博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
使用AOP的方式监测方法执行耗时
阅读量:7121 次
发布时间:2019-06-28

本文共 3013 字,大约阅读时间需要 10 分钟。

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

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关键字)创建相应的代理类。具体代码如下:

///     /// 标记要性能监测的类    ///     [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
(_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;        }    }

 

转载于:https://www.cnblogs.com/LoveJerryZhang/p/4365261.html

你可能感兴趣的文章
python用profile、hotshot、timeit协助程序性能优化
查看>>
Redis集群方案(codis)
查看>>
Spring整合MyBatis的几种方式
查看>>
Linux服务器开发常用的命令以及遇到的问题
查看>>
Welcome to WANGFRAME
查看>>
单点登录
查看>>
UIView类的UIViewAnimationWithBlocks扩展 和 使用core an...
查看>>
如何使用UIAutomation进行iOS 自动化测试
查看>>
centos
查看>>
Ubuntu单系统(一):苦难深重的校园网
查看>>
MyBatis 学习笔记一基本对象
查看>>
jenkins pipeline slack
查看>>
CoverFlow效果控件无限循环效果
查看>>
Android Activity生命周期应用 网络设置
查看>>
jenkins + svn + mvn + tomcat搭建CI服务
查看>>
easyui 之 datagrid动态列与列宽自适应
查看>>
jvm运行时数据区域解析
查看>>
spring RestTemplate基本使用与总结
查看>>
【MongoDB 可视化工具Robomongo】下载与安装
查看>>
hadoop 问题
查看>>