动态织入的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:在接口的方法上进行标记,如上文代码;

代码下载:ConsoleApplication1.rarConsoleApplication2.rar

posted @   陆敏技  阅读(5252)  评论(4编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 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——大语言模型本地部署的极速利器
Web Counter
Coupon for Contacts
点击右上角即可分享
微信分享提示