范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

。NET静态代码织入肉夹馍(Rougamo)

  肉夹馍是什么
  肉夹馍通过静态代码织入方式实现AOP的组件。.NET常用的AOP有Castle DynamicProxy、AspectCore等,以上两种AOP组件都是通过运行时生成一个代理类执行AOP代码的,肉夹馍则是在代码编译时直接修改原始方法IL代码,在原始方法内织入AOP代码的。
  .NET静态AOP的组件或许有人使用过PostSharp,这是一个功能完善且强大的静态代码织入组件,Postsharp有社区版,但可惜的是社区版不支持异步方法,肉夹馍的实现方式与Postsharp类似,同时也支持了异步方法,如果你仅仅使用了Postsharp方法层级的AOP代码织入功能,可以尝试使用肉夹馍来替代Postsharp。
  快速开始
  # 添加NuGet引用 dotnet add package Rougamo.Fody // 1.定义类继承MoAttribute,在该类中定义你在方法执行各阶段需要织入的代码 public class LoggingAttribute : MoAttribute {     public override void OnEntry(MethodContext context)     {         // 从context对象中能取到包括入参、类实例、方法描述等信息         Log.Info("方法执行前");     }      public override void OnException(MethodContext context)     {         Log.Error("方法执行异常", context.Exception);     }      public override void OnExit(MethodContext context)     {         Log.Info("方法退出时,不论方法执行成功还是异常,都会执行");     }      public override void OnSuccess(MethodContext context)     {         Log.Info("方法执行成功后");     } }  // 2.在需要织入代码的方法上应用LoggingAttribute public class Service {     [Logging]     public static int Sync(Model model)     {         // ...     }      [Logging]     private async Task Async(int id)     {         // ...     } } 通过实现空接口的方式进行代码织入
  在上面的示例中,我们通过在方法上应用Attribute进行AOP,这种方式目标明确但有些AOP代码我们可能希望应用于某一场景或某一层级,每个方法都去应用Attribute很繁琐,而且代码侵入严重。此时就可以考虑使用实现空接口( IRougamo<>  )的方式进行批量Attribute应用public interface IService : IRougamo { }  public interface IMyService : IService { }  public class MyService : IMyService { }
  上面的示例中, MyService  所有的public实例方法都将应用LoggingAttribute  ,你可能注意到我标红的部分了,为什么是public实例方法呢?这是默认值,你可以在继承MoAttribute  时通过重写Flags  属性来修改这一默认值,比如下面的示例中FullLoggingAttribute  将会应用于所有方法。另外需要注意的是Flags  属性在Attribute  直接应用到方法上时是无效的,比如LoggingAttribute  默认仅应用public实例方法,但像快速开始里的代码那样Async  方法虽然是private的但还是会应用LoggingAttribute  public class FullLoggingAttribute : LoggingAttribute {     public override AccessFlags Flags => AccessFlags.All; } 实例-Rougamo.OpenTelemetry
  在快速开始里介绍了肉夹馍两种常用的使用方式,更多的使用方式可以到github查看readme,在本篇文章中就不再做更多介绍了,接下来我将介绍使用肉夹馍的一个项目Rougamo.OpenTelemetry,如果你准备使用肉夹馍,但你还是不太清楚具体应该怎么使用,可以参考这个项目的代码实现。
  关于OpenTelemetry
  在了解 OpenTelemetry  前,你需要先了解APM(Application Performance Management/Monitor)  ,在这个微服务的时代,APM已经成为了必不可少的一部分,没有它整个系统对我们而言就是一个黑盒,你无法得知一个请求在微服务之间是如何调用如何完成,难以排查一个用户超时是哪个服务超时或出错。
  现在市面上有很多开源的APM比如Pinpoint, Zipkin, SkyWalking, CAT, jaeger等,虽说大家基本都是参考google的dapper论文设计出来的,但实现和功能侧重却大相径庭,为了对此形成一个规范,先后出现了 OpenTracing  和OpenCensus  ,并在此后合并为现在的OpenTelemetry  。
  OpenTelemetry的出现为APM的接入提供了一种可能"应用不需要在意具体的APM服务端使用的是Zipkin还是jaeger或是其他的情况下,应用只需要使用OpenTelemetry的SDK进行埋点,APM通过实现OTLP(OpenTelemetry Protocol)来支持OpenTelemetry数据格式即可",当前已经有些APM完全采用OpenTelemetry SDK作为默认的SDK比如jaeger,也有部分支持的APM比如skywalking。
  关于Rougamo.OpenTelemetry
  现在大部分流行的APM都有对应语言的SDK并且还实现了常用的I/O组件埋点,opentelemetry-dotnet也已经提供了包括 HttpClient  、SqlClient  、AspNetCore  等I/O埋点。
  虽说一般而言服务的耗时一般就在I/O部分,但由于开发人员的代码习惯不同、代码水平不同以及业务复杂度等情况,某些非I/O代码也会产生一定的耗时,同时在一个接口中可能会执行多次I/O操作,如果仅仅只有I/O埋点,可能很难分辨层次关系,此时可能需要一些本地辅助埋点, Rougamo.OpenTelemetry  便是用于添加本地埋点的组件。
  快速开始 # 启动项目引用Rougamo.OpenTelemetry.Hosting dotnet add package Rougamo.OpenTelemetry.Hosting # 添加埋点的项目引用Rougamo.OpenTelemetry dotnet add package Rougamo.OpenTelemetry public class Startup {     public void ConfigureServices(IServiceCollection services)     {         // ...          services.AddOpenTelemetryTracing(builder =>         {             builder                 .AddRougamoSource() // 初始化Rougamo.OpenTelemetry                 .AddAspNetCoreInstrumentation()                 .AddJaegerExporter();         });          // 修改Rougamo.OpenTelemetry默认配置         services.AddOpenTelemetryRougamo(options =>         {             options.ArgumentsStoreType = ArgumentsStoreType.Tag;         });     } }  class Service {     [return: ApmIgnore]     // 返回值不记录     [Otel] // 默认记录参数和返回值,需要通过ApmIgnoreAttribute来忽略不需要记录的参数或返回值     public async Task M1(             [ApmIgnore] string uid, // 该参数不记录             DateTime time)     {         // do something         return string.Empty;     }      [PureOtel] // 默认不记录参数和返回值,需要通过ApmRecordAttribute来记录指定的参数或返回值     public void M2(             [ApmRecord] double d1,  // 记录该参数             double d2)     {         // do something     } }  // 通过实现空接口织入 public interface ITestService : IRougamo {     // ... } public class TestService : ITestService {     // ... }
  Rougamo.OpenTelemetry  的埋点会对应生成一个名称为方法全名称(ClassFullName.MethodName)的LocalSpan  ,根据你使用的是OtelAttribute  还是PureOtelAttribute  决定默认是否记录参数和返回值。Rougamo.OpenTelemetry  是用来丰富APM埋点的,但是切记不要过度添加埋点,过多的埋点会让你的trace看起来很臃肿。关于Rougamo.OpenTelemetry更多的使用说明,详见github,github上的代码中包含了一个jaeger的示例代码,你可以从jaeger官网上下载一个all-in-one包快速运行一个jaeger服务端,然后启动示例项目,访问http://localhost:5000/test  接口,最后访问jaeger uihttp://localhost:16686  查看刚刚访问的test接口的trace数据。
  更多关于
  关于肉夹馍的应用情况
  写肉夹馍的动机是公司在使用 postsharp  做AOP,起初公司的代码是framework的并且基本使用同步方法,所以postsharp的免费版本是足足够用的,随着.NET的发展,公司的代码也逐渐从同步发展到异步从framework发展到core,然后我们通过购买付费版本的postsharp也能继续维持着,不过由于个人对postsharp的实现产生了兴趣,所以悄悄的建立了这个项目,但是由于个人比较懒,这个早在19年就建立了的项目直到21年才完成。
  在发布1.0.1之前,项目一直处于闭源状态,但在闭源状态下已经在公司内部发布了几个测试版本,其中1.0.0版本已经在公司测试环境沉淀了一个季度有余,现在已经将1.0.0版本发布到了线上使用中,发布在nuget.org上的1.0.1版本相对于1.0.0版本在代码上没有任何修改。 Rougamo  项目的TargetFramework是netstandard2.0  ,公司应用了Rougamo  的项目都是.NET Core3.1的,所以如果你的项目是.NET Core3.1的,你可以相对放心的使用(如果不着急应用,也推荐测试环境沉淀一下),如果你是其他版本,那么推荐你在测试环境沉淀一段时间,肉夹馍作为一个新项目,可能还会存在一些未知BUG,如果有任何BUG请反馈到github issue中。
  关于.NET的静态代码织入
  .NET的静态代码织入其实我了解的也不是特别多,我知道鼻祖应该是 Mono.Cecil  ,百度也能搜到很多它的介绍,然后就是很强大(但大部分功能收费)的Postsharp  ,以及对Mono.Cecil  进行封装,使其更易用的Fody,肉夹馍便是使用Fody  实现AOP代码织入的。静态代码织入在我观察下来使用得并不是很普遍,这或许是因为动态代理早已成熟的缘故吧。那么静态织入相对于动态代理有什么优势呢?
  说实话,开发肉夹馍很大一部分原因是个人兴趣,但这并不代表它没有优势,静态织入是在编译时进行的,静态织入只会让编译时间稍长些许,而动态代理的方式都是在应用启动时动态生成代理类来实现的,这个过程必定会占用些许时间,并且在这个初始化动作完成前,服务是不会进入就绪状态的,也就是这个服务暂时为不可用状态的,服务初始化时间越短,服务整体的可用性就会越好,这就是静态织入带来的优势。当然,有些朋友可能会认为这是在钻牛角尖,确实,很多时候我们可能认为这种耗时是微乎其微的,事实也确实如此,但做基础架构关注的就是这些微乎其微耗时,我们经常能看到java的一些技术博文上会写到他们做了很多字节码层面的优化,他们的这种优化很多时候只是优化了那么几个指令,单拎出来看着似乎没有多大的性能提升,然而在大流量高吞吐的服务中,这样优化的效果将会显现出来,静态织入也是如此,性能就是这样一点一点扣出来的。
  关于Fody
  .NET的开发者应该或多或少都听说甚至使用过ABP,它是.NET中非常流行的一套DDD框架了,如果你还看过ABP的源码,你或许见过Fody的影子,是的ABP也有使用到Fody,使用的是ConfigureAwait.Fody,我们在编写异步方法的时候经常会增加一个 .ConfigureAwait(false)  ,ConfigureAwait.Fody  的功能就是为异步调用默认加上这个方法调用。
  进入到Fody的github首页你将能看到很多借助于Fody开发的组件,我们也可以直接在nuget.org上以Fody为关键字进行搜索,你将能看到更多以Fody开发的组件,同时你可能还会发现,在下载量很高的NuGet包中有两个AOP相关实现MethodDecorator.Fody和MethodBoundaryAspect.Fody,早在我建立肉夹馍这个项目前我就看到了这两个项目,但当时的他们没有对异步方法的支持,就在这篇文章写到这里的时候我再次去查看了这两个项目,他们对异步的支持依旧不能满足我的需求,他们的 OnExit  方法都是在状态机在第一次返回也就是在遇到第一个await的时候执行的,这时候这个异步方法实际上可能并没有执行完毕,下面我会给一个例子,各位可以自己进行尝试。
  关于为什么我没有直接参与他们的项目,而是自己新建了一个项目,主要有两个原因:一是我有一丢丢懒,不确定这个项目我会投入多少精力并且什么时候去完成,事实也正如我的预期,两年过去了,二是我的英语有一丢丢差,IL方面我也不算老手,我担心有些问题交流起来有困难,所以最终也就独立建了肉夹馍这个项目了。 dotnet add package Rougamo.Fody dotnet add package MethodDecorator.Fody dotnet add package MethodBoundaryAspect.Fody             class Program {     static async Task Main(string[] args)     {         try         {             await Async();         }         catch         {         }     }      [RougamoLog]     //[MethodDecoratorLog]     //[MethodBoundaryAspectLog]     static async Task Async()     {         Console.WriteLine(1);         await Task.Delay(10);         Console.WriteLine(2);         throw new NotImplementedException("not implemented");     } }
  分别用三个Attribute运行上面的程序你会得到下面的输出,肉夹馍的异常信息是在输出2之后输出,exit信息在最后输出(也就是异步方法执行完毕后);MethodDecorator没有捕获到异步的异常,并且exit信息在输出2之前就输出了;MethodBoundaryAspect捕获到了异步的异常信息,但是exit信息在输出2之前输出了,也就是你无法在异步方法真正执行完毕后织入代码。 [Rougamo] on entry 1 2 [Rougamo] on exception: not implemented [Rougamo] on exit  [MethodDecorator] on init [MethodDecorator] on entry 1 [MethodDecorator] on exit 2  [MethodBoundaryAspect] on entry 1 [MethodBoundaryAspect] on exit 2 [MethodBoundaryAspect] on exception: not implemented 关于使用肉夹馍开发组件的注意事项
  最后如果你准备使用肉夹馍,并且你准备使用肉夹馍开发一个供他人使用的NuGet组件,那么你需要把项目文件(.csproj)中 Rougamo.Fody  的引用改成下面这样,不然你发布的NuGet其他人引用后将需要额外引用Fody,否则将无法进行代码织入,具体可以参考Rougamo.OpenTelemetry
  最后的最后,即使你不准备使用肉夹馍,也希望通过此文让你了解到静态代码织入,了解到 Mono.Cecil  和Fody  ,如果.NET能够发展壮大起来,那么静态代码织入也终将得到更大的发展。
  这篇文章中不论是Rougamo还是Rougamo.OpenTelemetry都没有进行完整的介绍,如果你准备使用它们,请移步github了解更多。
  https://github.com/inversionhourglass/Rougamo
  https://github.com/inversionhourglass/Rougamo.OpenTelemetry

古六大茶山之革登茶山本文由森醇悦原创首发于头条号森醇悦作者玺茗古六大茶山,一山一味,每个山头各具特色。一地理位置革登是古六大茶山之一,革登古茶山位于云南省西双版纳州景洪市勐腊县象眀乡境内。位于六大茶山OPPO新机曝光,骁龙888E4屏5000mAh,还有80W快充,售价感人作为国产四大手机品牌之一,OPPO在国内手机市场的影响力大家有目共睹,无论是偏远的乡镇,还是繁华的都市,几乎都能见到OPPO门店的身影。近些年来,OPPO也是连续畅联国内手机销量前3999降至2969,小米旗舰降至新低价,还要RedmiK50吗?支持MIUI13早买早享受,晚买享折扣,相对于新发布的旗舰手机来说老旗舰手机硬件配置不落后,价格更便宜,性价比更高。是的又到了老旗舰分享时间,其实说是老旗舰手机这是相对于新旗舰手机而言,小米11系仅售2769元,68W秒充5000万双主摄,骁龙8手机刷新低价新记录目前安卓手机阵营中几乎都在使用高通骁龙处理器,其中高通最新发布的顶级处理器骁龙8,是目前安卓顶级旗舰手机的首选。因为骁龙8芯片是采用的4纳米工艺制造,所以在性能方面更加强劲。作为顶OPPO性价比新机来了,骁龙888三星E4屏,不再高价低配其实很多时候,我们对一个品牌其实是有偏见的,就比如小米都需要抢购,都是在耍猴,而一向相对于比较低调的OPPOvivo,都会被人贴上高价低配的标签。但我们要知道的是,作为国内前几的手香烟市场大调整,这次3亿烟民被影响我国烟民数量超3亿之多,这也导致了我国拥有一个庞大的香烟市场,大部分烟民每月要花费数百乃至上千元在烟草行业中,你们有算过这笔账吗?要知道近几年时间中,烟草行业销售额都超万亿元,消费昨天割肉今天大涨,如何不被反复打脸?昨天市场大跌今天市场大涨,我相信不少人都很郁闷,昨天一割肉今天就大涨,其实这种情况在我们的投资生涯里面也是经常碰到,那如何去避免这样的事情发生呢?个人有几点经验分享一下希望对大家有这才是苹果真正的实力!外媒曝光iPhone14Pro概念机不要看iPhone最近几年缺乏创新,但销量和口碑都一直遥遥领先,尤其是在高端机市场,更是属于一枝独秀的存在。究其原因,还是因为iPhone手机的质量过硬系统流畅和性能强悍,哪怕使用OPPO首款处理器将采台积电6纳米制程打造,预计2024年上市OPPOOPPO的IC设计子公司正在研发手机处理器,未命名的处理器将采用台积电6纳米制程,并2023年量产,2024年问世。OPPO还计划推出更强大节能整合基频芯片的后继款处理器。华为Mate50基本确定,芯片5G都有了?花粉幸福来得太突然自从华为被某些品牌联合制裁之后,似乎陷入了一种困难的境地。华为是否能够克服5G网络的技术限制,华为又能否再次登顶中国数码手机品牌,走向世界呢?正因如此,华为新的手机的动向与消息,也61年前加加林上空,今天马斯克3。5亿太空旅宇宙那么大去看看导读61年了,商业航天的想象力正在被释放。61年前的今天,27岁的苏联宇航员尤里加加林,乘坐东方1号飞船登上太空,实现了人类首次遨游太空的壮举。后来,每年的这一天被定为载人空间飞行
毫无悬念当选状元!山东小伙王岚嵚的CBA首秀打完了!表现如何?下场继续加油!赛季首胜!做自己!王岚嵚在打完自己首场CBA正式比赛之后,在社交媒体上写道。今天,同曦男篮打响了新赛季的首场比赛,凭借着00后小将林葳的压哨绝杀,以2分的优势险胜天津半年血亏44亿!被特斯拉霸凌的中国车企,开始卖惨了文金错刀频道2019年,最惨的造车大佬是蔚来创始人李斌。那年蔚来亏掉112亿元,新车不被看好,股价跌到1美元,来到退市边缘,所有人都怀疑李斌走不下去了。当时,小鹏汽车创始人何小鹏还贝泰妮的品牌新拼图再造一个轻医美版的薇诺娜?日前,贝泰妮旗下新抗衰高端品牌AOXMED瑷科缦的官网正式上线,根据信息显示,该品牌主打3R护肤理念(修护REPAIR赋活REJUVE维持RETAIN),并致力于将功效护肤产品与专iPhone14破发,国产旗舰机会来了?双十一这三大品牌值得关注今年苹果的四款新品手机命途迥异,iPhone14Pro和ProMax无疑是成功的。加价,排队成为了关键词。然而标准版的iPhone14以及被寄予厚望的14Plus,并没有能复制两位传音旗下品牌TECNO海外推出Pova4系列新机搭载联发科G99前不久,传音的旗下品牌Infinix在印度等海外市场推出了一款2亿像素主摄180W快充的InfinixZeroUltra手机,不过传音旗下的品牌并非仅有Infinix,近期另一个旗祝福ampampamp故乡祝福文李旭霞诵涛声依旧仰首是春,俯首是秋月圆是画月亏是诗回眸这一年跋涉山水夜里爬行挣扎生活真诚的祝福天涯或咫尺如清波一泓清滢滢水灵灵真诚的祝福阳光温暖凝香成卷静然的岁月中丰盈了心灵降温了,吃羊肉吃牛肉,不如吃这肉,滋补暖身不上火,安稳度深秋降温了,吃羊肉吃牛肉,不如吃这肉,滋补暖身不上火,安稳度深秋不管是南方还是北方,最近这段日子都降温了,而且还是突然间的,这几天肯定不少人感冒了吧?记得多添加衣物,最近我也是哪哪都不大幅下跌丨泸州主城区9月销售数据出炉近日,泸州市房屋产权交易服务中心在泸州市住房和城乡建设局官方网站公布了2022年9月泸州市主城区新建商品住房销售信息和2022年9月泸州市主城区新建商品住房在售项目销售排名。下面来江西少有人问津的古镇,来过的人想摆烂和养老,距武汉3h高铁秋日生活打卡季江西有个古镇,低调了很多年,有着悠久的历史故事,古老的小镇,依偎在了山水间,多少往事,都在水中静悄悄地流淌着,生态美景,如诗如画,在自然的风景中,发发呆,都能轻易遇见山人行摄196游览中原大岭老君山感受中华文化真髓山人行摄196游览中原大岭老君山感受中华文化真髓老君山原名景室山,是八百里伏牛山脉的主峰,海拔2297米。老君山有两千多年道教文化历史,是我国道教名山。传说老子传道德经后,告别函谷争冠难了!孙准浩踢4场就走,泰山含泪放人,缺席多久看韩国脸色中超联赛已经进入为期两周左右的休赛期,根据多方消息显示,中超再次开赛的时间锁定在10月30日前后,再加上仍然需要年内完成本赛季,那么与世界杯发生冲突是必然的。由于今年世界杯持续时间