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($"方法执行之前,args:{args}");
} public void BeforeAction(object?[]? args, object result)
{
Console.WriteLine($"方法执行之后,args:{args},result:{result}");
throw new NotImplementedException();
}
}

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)
{
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);

4.Demo

  大家可直接访问我的,gitee

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

.NET Core 实现动态代理做AOP(面向切面编程)的更多相关文章

  1. AOP(面向切面编程)大概了解一下

    前言 上一篇在聊MemoryCache的时候,用到了Autofac提供的拦截器进行面向切面编程,很明显能体会到其优势,既然涉及到了,那就趁热打铁,一起来探探面向切面编程. 正文 1. 概述 在软件业, ...

  2. AOP 面向切面编程, Attribute在项目中的应用

    一.AOP(面向切面编程)简介 在我们平时的开发中,我们一般都是面对对象编程,面向对象的特点是继承.多态和封装,我们的业务逻辑代码主要是写在这一个个的类中,但我们在实现业务的同时,难免也到多个重复的操 ...

  3. [转] AOP面向切面编程

    AOP面向切面编程 AOP(Aspect-Oriented Programming,面向切面的编程),它是可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术. ...

  4. 【原创】Android AOP面向切面编程AspectJ

    一.背景: 在项目开发中,对 App 客户端重构后,发现用于统计用户行为的友盟统计代码和用户行为日志记录代码分散在各业务模块中,比如在视频模块,要想实现对用户对监控点的实时预览和远程回放行为进行统计, ...

  5. 从壹开始前后端分离【 .NET Core2.0 +Vue2.0 】框架之十 || AOP面向切面编程浅解析:简单日志记录 + 服务切面缓存

    代码已上传Github+Gitee,文末有地址 上回<从壹开始前后端分离[ .NET Core2.0 Api + Vue 2.0 + AOP + 分布式]框架之九 || 依赖注入IoC学习 + ...

  6. Spring:AOP面向切面编程

    AOP主要实现的目的是针对业务处理过程中的切面进行提取,它所面对的是处理过程中的某个步骤或阶段,以获得逻辑过程中各部分之间低耦合性的隔离效果. AOP是软件开发思想阶段性的产物,我们比较熟悉面向过程O ...

  7. Spring Boot2(六):使用Spring Boot整合AOP面向切面编程

    一.前言 众所周知,spring最核心的两个功能是aop和ioc,即面向切面和控制反转.本文会讲一讲SpringBoot如何使用AOP实现面向切面的过程原理. 二.何为aop ​ aop全称Aspec ...

  8. 详细解读 Spring AOP 面向切面编程(二)

    本文是<详细解读 Spring AOP 面向切面编程(一)>的续集. 在上篇中,我们从写死代码,到使用代理:从编程式 Spring AOP 到声明式 Spring AOP.一切都朝着简单实 ...

  9. 谈一谈AOP面向切面编程

    AOP是什么 : AOP面向切面编程他是一种编程思想,是指在程序运行期间,将某段代码动态的切入到指定方法的指定位置,将这种编程方式称为面向切面编程 AOP使用场景 : 日志 事务 使用AOP的好处是: ...

随机推荐

  1. .Net Core——用SignalR撸个游戏

    之前开内部培训,说到实时web应用这一块讲到了SignalR,我说找时间用它做个游戏玩玩,后面时间紧张就一直没安排.这两天闲了又想起这个事,考虑后决定用2天时间写个斗D主,安排了前端同学写客户端,我写 ...

  2. Spring Cloud中五花八门的分布式组件我到底该怎么学

    分布式架构的演进 在软件行业,一个应用服务随着功能越来越复杂,用户量越来越大,尤其是互联网行业流量爆发式的增长,导致我们需要不断的重构应用的结构来支撑庞大的用户量,最终从一个简单的系统主键演变成了一个 ...

  3. 【模板】二分图最大匹配(匈牙利算法)/洛谷P3386

    题目链接 https://www.luogu.com.cn/problem/P3386 题目大意 给定一个二分图,其左部点的个数为 \(n\),右部点的个数为 \(m\),边数为 \(e\),求其最大 ...

  4. 巩固javaweb的第二十五天

    常用的验证 1. 非空验证 // 验证是否是空 function isNull(str) { if(str.length==0) return true; else return false; } 2 ...

  5. adverb

    An adverb is a word or an expression that modifies a verb, adjective, another adverb, determiner [限定 ...

  6. Hive(二)【数据类型、类型转换】

    目录 一.基本数据类型 案例实操 二.集合数据类型 案例实操 Map类型 三.类型转换 1.隐式类型转换 2.显示(强制)类型转换 一.基本数据类型 HIVE MySQL JAVA 长度 例子 TIN ...

  7. flink01--------1.flink简介 2.flink安装 3. flink提交任务的2种方式 4. 4flink的快速入门 5.source 6 常用算子(keyBy,max/min,maxBy/minBy,connect,union,split+select)

    1. flink简介 1.1 什么是flink Apache Flink是一个分布式大数据处理引擎,可以对有限数据流(如离线数据)和无限流数据及逆行有状态计算(不太懂).可以部署在各种集群环境,对各种 ...

  8. css相关,flex布局全通!

    寻根溯源话布局 一切都始于这样一个问题:怎样通过 CSS 简单而优雅的实现水平.垂直同时居中. 记得刚开始学习 CSS 的时候,看到 float 属性不由得感觉眼前一亮,顺理成章的联想到 Word 文 ...

  9. supervise安装与使用

    确认当前是否已经安装which supervise/usr/local/bin/supervise 软件下载安装-------------------------------------------- ...

  10. 【JS】toLocaleString 日期格式,千分位转换

    https://blog.csdn.net/Seven521m/article/details/108866881 类似于c里printf(m%)的意思 可以指定整数最少位数,小数最少与最多位数,有效 ...