动态织入的AOP实现
动态织入的AOP实现,有两种方法:
第一类,借助于Remoting命名空间下的几个类,通过获取当前上下文及反射的机制来实现,这需要被AOP的类需要继承自arshalByRefObject
或者ContextBoundObject;
第二类,原理是基于动态代理的思想,即在运行时动态构造一个原有类的子类,这样就可以在子类的重载方法中插入额外代码。
这两类方法,都有显著的不足,前者直接要求我们继承固定类,后者呢,除非父类方法被定义为virtual,或者方法定义于某个接口,否则就不能被重载,这就是得“拦截”并不是可以对任意的方法进行的。
动态织入局限于CLR的限制,不能实现对任何方法进行AOP,如果要突破这个限制,只能采用静态织入的方法,静态织入采用。静态织入突破OO设计模式,可以拦截所有的方法甚至构造函数或属性访问器,因为它是直接修改IL。还有,因为它在运行前修改原有程序集,也就基本不存在运行时的性能损失问题了。它的不足,一方面是框架较复杂,实现较麻烦,依赖于对底层的IL指令集的操纵;
一:继承自ContextBoundObject的实现
帮助类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | public class SecurityAspect : IMessageSink { internal SecurityAspect(IMessageSink next) { _next = next; } private IMessageSink _next; public IMessageSink NextSink { get { return _next; } } public IMessage SyncProcessMessage(IMessage msg) { Preprocess(msg); IMessage returnMethod = _next.SyncProcessMessage(msg); return returnMethod; } public IMessageCtrl AsyncProcessMessage(IMessage msg, IMessageSink replySink) { throw new InvalidOperationException(); } private void Preprocess(IMessage msg) { if (!(msg is IMethodMessage)) return ; IMethodMessage call = msg as IMethodMessage; Type type = Type.GetType(call.TypeName); string callStr = type.Name + "." + call.MethodName; Console.WriteLine( "Security validating : {0} for {1}" , callStr, Environment.UserName); // call some security validating code } } public class SecurityProperty : IContextProperty, IContributeObjectSink { public IMessageSink GetObjectSink(MarshalByRefObject o, IMessageSink next) { return new SecurityAspect(next); } public string Name { get { return "SecurityProperty" ; } } public void Freeze(Context newContext) { } public bool IsNewContextOK(Context newCtx) { return true ; } } [AttributeUsage(AttributeTargets.All)] public class SecurityAttribute : ContextAttribute { public SecurityAttribute() : base ( "Security" ) { } public override void GetPropertiesForNewContext(IConstructionCallMessage ccm) { ccm.ContextProperties.Add( new SecurityProperty()); } } |
调用方:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | class Program { static void Main( string [] args) { SampleClass s = new SampleClass(); s.DoSomething(); } } [Security] [Tracing] public class SampleClass: ContextBoundObject { public void DoSomething() { Console.WriteLine( "do something" ); } } |
二:Virtual方法及接口的实现
帮助类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | public class LogHandler : ICallHandler { /// <summary> /// 执行顺序 /// </summary> public int Order { get ; set ; } public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext) { Console.WriteLine( "方法名: {0}" , input.MethodBase.Name); Console.WriteLine( "参数:" ); for ( var i = 0; i < input.Arguments.Count; i++) { Console.WriteLine( "{0}: {1}" , input.Arguments.ParameterName(i), input.Arguments[i]); } Console.WriteLine( "方法执行前的处理" ); var retvalue = getNext()(input, getNext); Console.WriteLine( "方法执行后的处理" ); return retvalue; } } public class LogHandlerAttribute : HandlerAttribute { public override ICallHandler CreateHandler(IUnityContainer container) { return new LogHandler(); } } |
调用方:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | public interface ISample { [LogHandler] void DoSomething(); void DoSomethingNoAop(); } class Sample1 : ISample { public void DoSomething() { Console.WriteLine( "Sample1 do something" ); } public void DoSomethingNoAop() { Console.WriteLine( "Sample1 do something no aop" ); } } public class SampleClass { [LogHandler] public virtual void SampleVirtual() { Console.WriteLine( "Virtual method" ); } public void Sample() { Console.WriteLine( "Sampe method" ); } } class Program { static void Main() { //针对接口 var container1 = new UnityContainer() .AddNewExtension<Interception>() .RegisterType<ISample, Sample1>(); container1 .Configure<Interception>() .SetInterceptorFor<ISample>( new InterfaceInterceptor()); container1 .Configure<Interception>() .SetInterceptorFor<SampleClass>( new VirtualMethodInterceptor()); var sample1 = container1.Resolve<ISample>(); sample1.DoSomething(); sample1.DoSomethingNoAop(); //针对虚拟方法 var sample2 = container1.Resolve<SampleClass>(); sample2.SampleVirtual(); sample2.Sample(); Console.ReadKey(); } } |
可以看到,第二种方法是用Unity实现的,关于Unity,这里多说两句:
Unity的AOP可以从3种标记的情况拦截:
TransparentProxyInterceptor:直接在类的方法上进行标记,但是这个类必须继承MarshalByRefObject;
VirtualMethod:直接在类的虚方法上进行标记,如上文代码;
InterfaceInterceptor:在接口的方法上进行标记,如上文代码;
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· .NET周刊【3月第1期 2025-03-02】
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器