文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

.NETCore利用动态代理实现AOP(面向切面编程)

2024-04-02 19:55

关注

1.介绍

1.1 动态代理作用

用动态代理可以做AOP(面向切面编程),进行无入侵式实现自己的扩展业务,调用者和被调用者之间的解耦,提高代码的灵活性和可扩展性,比如:日志记录、性能统计、安全控制、事务处理、异常处理等等。本方式实现思路用的.NET Core原生的DispatchProxy类,再加《特性标记》+《Handle接口》达到无入侵式扩展 ,有兴趣的朋友,自行改进一下,封装成组件。

有什么做的不好的或者建议,希望大家及时提出,帮助改进。

代码上传在gitee:https://gitee.com/luoxiangbao/dynamic-proxy.git

1.2 原生DispatchProxy类介绍

DispatchProxy我去看了一下源码,和我设想的差不多,就是Emit类库直接编写IL语言,动态生成类和方法,然后在方法里调用Invoke方法,这个时候就我们只需要重写Invoke方法,具体实现由我们自己管控。其性能很高,几乎和我们写好的C#编译成IL没多大区别,大家用的Autofac的AOP,我也看了一下,底层用的是Castle.Core类库,而Castle.Core底层还是用的Emit方式实现,只是思路不同。

便于理解我给大家贴一下源码:

1.定义抽象DispatchProxy类的Invoke元数据

 2.Emit类库直接编写IL语言,为代理类添加调用Invoke方法代码

1.3简单介绍一下:IL代码

IL是.NET框架中间语言(Intermediate Language),编译器可以直接将源程序编译为.exe或.dll文件,而CLR(公共语言运行时)执行的是IL语言,不是C#高级编程语言,IL代码是一种近似于指令式的代码语言,与汇编语言比较相近,给大家做个案例对比一下。

C#代码:

class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");
        }
    }

IL代码:

IL_0000:  nop
IL_0001:  ldstr      "Hello World!"
IL_0006:  call       void [System.Console]System.Console::WriteLine(string)
IL_000b:  nop
IL_000c:  ret

有兴趣的朋友自己也可以去实现。接下来进入正题,我们怎么利用DispatchProxy自己造轮子!!!

2.实现

2.1 继承DispatchProxy

核心类就是,DispatchProxy。这是.NET core 原生的。会帮我们创建一个代理类

internal class DynamicProxy<T> : DispatchProxy
    {
        public T? decorated { get; set; }//目标类
        public Action<object?[]?>? _afterAction { get; set; }  // 动作之后执行
        public Action<object?[]?, object>? _beforeAction { get; set; } // 动作之前执行
        protected override object? Invoke(MethodInfo? targetMethod, object?[]? args)
        {
            Exception exception = null;
            AfterAction(args);
            object result = null;
            try
            {
                //调用实际目标对象的方法
                result = targetMethod?.Invoke(decorated, args);
            }
            catch (Exception ex)
            {
                exception = ex;
            }
            BeforeAction(args, result);
            //调用完执行方法后的委托,如果有异常,抛出异常
            if (exception != null)
            {
                throw exception;
            }
            return result;
        }

        /// <summary>
        /// 创建代理实例
        /// </summary>
        /// <param name="decorated">代理的接口类型</param>
        /// <param name="afterAction">方法执行前执行的事件</param>
        /// <param name="beforeAction">方法执行后执行的事件</param>
        /// <returns></returns>
        public T Create(T decorated, Action<object?[]?> afterAction, Action<object?[]?, object> beforeAction)
        {
            object proxy = Create<T, DynamicProxy<T>>(); // 调用DispatchProxy 的Create  创建一个新的T
            DynamicProxy<T> proxyDecorator = (DynamicProxy<T>)proxy;
            proxyDecorator.decorated = decorated;
            //把自定义的方法委托给代理类
            proxyDecorator._afterAction = afterAction;
            proxyDecorator._beforeAction = beforeAction;
            return (T)proxy;
        }


        private void AfterAction(object?[]? args)
        {
            try
            {
                _afterAction.Invoke(args);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"执行之前异常:{ex.Message},{ex.StackTrace}");
            }
        }

        private void BeforeAction(object?[]? args, object? result)
        {
            try
            {
                _beforeAction.Invoke(args, result);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"执行之后异常:{ex.Message},{ex.StackTrace}");
            }
        }


    }

2.2 定义handle接口

这个接口定义:执行之前、执行之后两个方法。用来实现具体业务逻辑的处理

internal interface IInterceptor
    {
        /// <summary>
        /// 执行之前
        /// </summary>
        /// <param name="args">参数</param>
        void AfterAction(object?[]? args);


        /// <summary>
        /// 执行之后
        /// </summary>
        /// <param name="args">参数</param>
        /// <param name="result">结果</param>
        void BeforeAction(object?[]? args, object result);
    }

2.3 定义AOP特性

1.用来标记类具体使用哪个handle的实现来处理业务。

2. 特性定义Type属性决定创建代理类的时候,具体使用哪个handle实现

[AttributeUsage(AttributeTargets.Class)]
    internal class InterceptAttribut : Attribute
    {
        public Type Type { get; set; }
        public InterceptAttribut(Type type) 
        {
            this.Type = type;
        }
    }

2.4 定义创建代理类的工厂

这里就是来组装代理类与handle实现的地方。

internal class ProxyFactory
    {

        /// <summary>
        /// 创建代理实例
        /// </summary>
        /// <param name="decorated">代理的接口类型</param>
        /// <returns></returns>
        public static T Create<T>()
        {
            var decorated = ServiceHelp.GetService<T>();
            var type = decorated.GetType();
            var interceptAttribut = type.GetCustomAttribute<InterceptAttribut>();
            var interceptor = ServiceHelp.GetService<IInterceptor>(interceptAttribut.Type);
            //创建代理类
            var proxy = new DynamicProxy<T>().Create(decorated, interceptor.AfterAction, interceptor.BeforeAction);
            return proxy;
        }

    }

1.拿到具体类,获取Type,获取我们上面定义的特性,通过特性的属性,用来创建handle实例

2.ServiceHelp是我定义的一个来获取实例化的容器帮助类。这个用.NET CORE 原始的IOC。大家可替换成autofac

3.创建化代理实例,把实例和handle实现的具体方法:AfterAction、BeforeAction传入。用于代理类执行的时候,进行真正的调用

2.5 定义ServiceHelp

这里大家可自行发挥

public static class ServiceHelp
    {

        public static IServiceProvider? serviceProvider { get; set; }

        public static void BuildServiceProvider(IServiceCollection serviceCollection)
        {
            //构建容器
            serviceProvider = serviceCollection.BuildServiceProvider();
        }

        public static T GetService<T>(Type serviceType)
        {
            return (T)serviceProvider.GetService(serviceType);
        }

        public static T GetService<T>()
        {
            return serviceProvider.GetService<T>();
        }
    }

3.测试

3.1 定义handle实现

    internal class AOPTest : IInterceptor
    {
        public void AfterAction(object?[]? args)
        {
            Console.WriteLine($"AOP方法执行之前,args:{args}");
            throw new Exception("异常测试(异常,但依然不能影响程序执行)");
        }

        public void BeforeAction(object?[]? args, object result)
        {
            Console.WriteLine($"AOP方法执行之后,args:{args},result:{result}");
        }
    }

3.2 定义Service接口

    internal interface ITestService
    {
        public int Add(int a, int b);
    }

3.3实现Service接口

定义实现,并且在类上加上,AOP交给哪个handle

    [InterceptAttribut(typeof(AOPTest))]
    internal class TestService : ITestService
    {
        public int Add(int a, int b)
        {
            Console.WriteLine($"正在执行--》Add({a},{b})");
            throw new Exception("方法执行--》测试异常");
            return a + b;
        }
    }

3.4 大功告成

1.创建容器,把我们自己的业务实现都注册好

2.通过工厂进行,动态创建代理实例

// See https://aka.ms/new-console-template for more information
using Infrastructure.DynamicProxy;
using Microsoft.Extensions.DependencyInjection;

Console.WriteLine("Hello, World!");
//容器注册
IServiceCollection serviceCollection = new ServiceCollection();
serviceCollection.AddTransient(typeof(AOPTest));
serviceCollection.AddTransient<ITestService, TestService>();
//构建容器
ServiceHelp.BuildServiceProvider(serviceCollection);
//用工厂获取代理实例
var s = ProxyFactory.Create<ITestService>();
var sum = s.Add(1, 2);
Console.WriteLine("执行完毕=====>" + sum);

3.5 效果

4.Demo

大家可直接访问我的,gitee

https://gitee.com/luoxiangbao/dynamic-proxy.git

以上就是.NET Core利用动态代理实现AOP(面向切面编程)的详细内容,更多关于.NET Core实现AOP的资料请关注编程网其它相关文章!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯