首页 > 编程语言 >.Net Core(六) 面向切面编程

.Net Core(六) 面向切面编程

时间:2024-03-04 14:47:56浏览次数:29  
标签:Core logger 关注点 public 切面 AOP 日志 Net

简介

面向切面编程(AOP,Aspect-Oriented Programming)是一种编程范式,旨在增强现有的面向对象编程(OOP,Object-Oriented Programming)范式。AOP 通过在程序执行过程中动态地将横切关注点(cross-cutting concerns)从它们所影响的对象中分离出来,并将其模块化,以便重用和管理。

在传统的面向对象编程中,程序功能被分解为对象及其方法,这些方法通常是面向单一功能的。但在实际应用中,一些功能可能会横跨多个对象和方法,这些功能通常被称为横切关注点,比如日志记录、安全性、事务管理等。这些横切关注点散布在整个应用程序中,导致了代码的重复和耦合性增加,难以维护和扩展。

AOP 通过将这些横切关注点从业务逻辑中分离出来,形成独立的切面(Aspect),然后将切面与主要的业务逻辑模块进行连接,实现了横切关注点的重用和集中管理。这样一来,切面可以在程序执行的特定点(例如方法调用前、方法调用后、方法异常时等)插入代码,从而实现特定的功能,而不需要修改原始业务逻辑代码。

术语

在 AOP(面向切面编程)中,有一些主要的术语,它们有助于理解和使用该编程范式:

  1. 切面(Aspect):切面是横切关注点的模块化单元。它包含了一组通知以及相应的切点表达式。通知定义了在何时、何地、如何处理横切关注点的逻辑,而切点表达式则定义了何处应用这些通知。

  2. 通知(Advice):通知是切面中具体的行为逻辑。在 AOP 中,通知定义了在程序执行过程中横切关注点被触发时应该执行的代码。常见的通知类型包括前置通知(Before advice)、后置通知(After advice)、环绕通知(Around advice)、异常通知(After-throwing advice)和返回通知(After-returning advice)。

  3. 连接点(Join Point):连接点是在程序执行过程中能够被切面通知的具体点。例如,方法调用、方法执行、对象创建等都是连接点。

  4. 切点(Pointcut):切点是连接点的集合,它定义了切面在何处应该被执行。通常使用切点表达式来描述切点,该表达式匹配连接点的模式。

  5. 目标对象(Target Object):目标对象是应用程序中真正具有业务逻辑的对象。在 AOP 中,切面通过通知来增强目标对象的功能。

  6. 代理(Proxy):代理是在运行时创建的对象,它包装了目标对象,并提供了额外的功能,例如应用切面中定义的通知。

  7. 织入(Weaving):织入是将切面与目标对象连接起来以创建新的代理对象的过程。织入可以在编译时、类加载时或运行时进行。在 AOP 中,织入是将切面的行为应用到目标对象的过程。

举例说明

假设你有一个电商网站,用户可以在该网站上购买商品。在这个网站中,用户的主要操作包括浏览商品、添加商品到购物车、填写订单信息和支付订单等。这些操作构成了用户的主要业务逻辑。

但是,除了用户的主要操作外,还有一些额外的功能需要处理,比如日志记录、安全验证、性能监控等。这些功能并不直接与用户的主要操作相关,但却是整个网站运行所必需的。

现在,我们使用面向切面编程(AOP)来描述这个情景:

  1. 切面(Aspect):切面是横切关注点的模块化单元。在我们的例子中,日志记录、安全验证、性能监控等是切面的一部分。

  2. 通知(Advice):通知是切面中具体的行为逻辑。在我们的例子中,通知就是针对特定切点(连接点)执行的额外代码,比如在方法调用前后记录日志、验证用户权限,或者监测方法执行时间等。

  3. 连接点(Join Point):在用户操作的过程中,比如浏览商品、添加商品到购物车、填写订单信息和支付订单等都是连接点。即,这些是切面可以介入的地方。

  4. 切点(Pointcut):切点是连接点的集合,它定义了切面应该在哪些连接点处进行织入。在这个例子中,浏览商品、添加商品到购物车、填写订单信息和支付订单等操作的集合就是切点。

  5. 目标对象(Target Object):在这个例子中,用户操作的过程就是目标对象。用户的主要业务逻辑是浏览商品、添加商品到购物车、填写订单信息和支付订单。

  6. 代理(Proxy):日志记录、安全验证、性能监控可以被看作是代理,它们为用户的操作提供了额外的功能,比如记录日志、验证用户身份、监控系统性能等。

  7. 织入(Weaving):织入是将日志记录、安全验证、性能监控的功能与用户操作的过程相连接的过程。这样,日志记录、安全验证、性能监控就在用户的操作过程中被执行了。

 不使用AOP代码

// HomeController.cs
public class HomeController : Controller
{
    private readonly ILogger<HomeController> _logger;

    public HomeController(ILogger<HomeController> logger)
    {
        _logger = logger;
    }

    public IActionResult Index()
    {
        _logger.LogInformation("User browsed products.");
        // 业务逻辑:浏览商品
        return View();
    }

    public IActionResult AddToCart()
    {
        _logger.LogInformation("User added a product to the cart.");
        // 业务逻辑:添加商品到购物车
        return View();
    }

    public IActionResult Checkout()
    {
        _logger.LogInformation("User proceeded to checkout.");
        // 业务逻辑:填写订单信息
        return View();
    }

    public IActionResult Pay()
    {
        _logger.LogInformation("User paid for the order.");
        // 业务逻辑:支付订单
        return View();
    }
}

使用AOP代码

// LoggingInterceptor.cs
public class LoggingInterceptor : AbstractInterceptor
{
    private readonly ILogger<LoggingInterceptor> _logger;

    public LoggingInterceptor(ILogger<LoggingInterceptor> logger)
    {
        _logger = logger;
    }

    public async Task Invoke(AspectContext context, AspectDelegate next)
    {
        // 记录用户操作
        _logger.LogInformation($"User {context.ImplementationMethod.Name}");

        // 执行被拦截的方法
        await next(context);
    }
}

// HomeController.cs
[LoggingInterceptor]
public class HomeController : Controller
{
    public IActionResult Index()
    {
        // 业务逻辑:浏览商品
        return View();
    }

    public IActionResult AddToCart()
    {
        // 业务逻辑:添加商品到购物车
        return View();
    }

    public IActionResult Checkout()
    {
        // 业务逻辑:填写订单信息
        return View();
    }

    public IActionResult Pay()
    {
        // 业务逻辑:支付订单
        return View();
    }
}

在这个示例中,我们使用了 AOP 的方式来实现日志记录的功能。通过使用 AspectCore 框架,我们定义了一个名为 LoggingInterceptor 的拦截器,并在该拦截器中实现了日志记录的逻辑。在 HomeController 中,我们使用 [LoggingInterceptor] 属性将该拦截器应用到了控制器的所有方法上。这样,业务逻辑和日志记录的关注点被明确地分离开来,使代码更加清晰和可维护。

使用中间件

有时我会想中间件也可以实现这个日志记录和业务分离啊

我们创建一个自定义的日志记录中间件:

// LoggingMiddleware.cs
public class LoggingMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ILogger<LoggingMiddleware> _logger;

    public LoggingMiddleware(RequestDelegate next, ILogger<LoggingMiddleware> logger)
    {
        _next = next;
        _logger = logger;
    }

    public async Task Invoke(HttpContext context)
    {
        // 记录用户操作
        _logger.LogInformation($"User requested: {context.Request.Path}");

        // 继续请求处理管道中的下一个中间件
        await _next(context);
    }
}

然后,在 Startup.cs 中注册和使用这个中间件:

// Startup.cs
public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        // 配置其他服务
    }

    public void Configure(IApplicationBuilder app)
    {
        // 配置其他中间件

        app.UseMiddleware<LoggingMiddleware>();

        // 配置其他中间件
    }
}

这样,我们就将日志记录的逻辑剥离到了一个中间件中,使得它与业务逻辑分离开来。在每次请求进入管道时,中间件都会记录用户操作的日志。

既然中间件可以实现,我们为什么还要AOP呢?

在中间件中实现日志记录可能会限制我们对日志记录逻辑的灵活控制。例如,我们可能希望根据不同的条件记录不同级别的日志,或者在特定情况下禁用日志记录。使用中间件可能无法满足这些需求。

优点

  1. 模块化:AOP允许将横切关注点(如日志记录、安全性、事务管理等)与核心业务逻辑分离,使得代码更易于理解、维护和重用。

  2. 可维护性:通过将横切关注点集中处理,AOP降低了代码重复性,减少了代码中的冗余,使得修改和维护更加容易。

  3. 关注分离:AOP通过将横切关注点从业务逻辑中分离出来,使得代码更加关注于核心业务逻辑,提高了代码的清晰度和可读性。

  4. 集中管理:AOP允许将各种横切关注点集中管理,便于统一控制和管理,提高了代码的可控性和可维护性。

  5. 横切关注点重用:AOP允许将一些横切关注点(如日志记录、事务管理等)在不同的模块中重用,提高了代码的灵活性和复用性。

缺点

  1. 学习曲线:AOP的概念相对传统的面向对象编程(OOP)来说比较抽象,可能需要一定时间来理解和掌握。

  2. 增加复杂性:使用AOP可能会增加代码的复杂性,特别是对于初学者来说,需要谨慎使用以避免引入不必要的复杂性。

  3. 运行时性能开销:一些AOP框架在运行时会增加一定的性能开销,尤其是在大型或高并发的应用中,可能会对性能产生一定影响。

  4. 调试困难:由于AOP会将一些关注点分离到不同的模块中,可能会增加调试代码的难度,特别是当一个横切关注点被多个连接点调用时。

  5. 潜在滥用:过度使用AOP可能导致代码的可读性和可维护性下降,特别是当横切关注点过多或不合理时,可能会导致代码变得混乱和难以理解。

 

标签:Core,logger,关注点,public,切面,AOP,日志,Net
From: https://www.cnblogs.com/mchao/p/18051593

相关文章

  • .NET Core AutoMapping 对象映射器转换
    先在NuGet程序包里下载这个文件然后新建一个类继承:ProfileusingAutoMapper;usingRBAC_Domain;usingRBAC_Domain.DTO;namespaceRBAC_Service.MyProFiles{///<summary>///转换对象映射器类///</summary>publicclassMappingProfile:Profile......
  • .Net Core AutoFac 批量注入
    先从NuGet包里下载这2个文件然后创建一个类继承:Autofac.ModuleusingSystem.Reflection;usingAutofac;namespaceRBAC_Api{publicclassRbacModule:Autofac.Module{///<summary>///重写Load方法///</summary>///<pa......
  • c#之asp.net的管道处理模式pipeline
    管道在进入管道之前首先要知道asp.netisApi所有的请求是由IIS转发给asp.netisApiHttpWorkerRequest监听asp.netisApi中的队列,HttpWorkerRequest是管道的执行入口 注册中间件的过程在响应请求的时候会触发事件,需要Config中配置以下是HtttpAplacation中的部分事件,在请求进......
  • .net core UI测试
    背景从后端测试的角度来看前端测试;后端测试  黑盒测试:自动化接口测试,不关心内部实现,只关心入参出参,出于用户角度来测试完整功能;  白盒测试:代码层单元测试,关心内部实现,聚焦核心方法,出于开发角度来测试部分核心功能;前端测试  黑盒测试:(待实现)  白盒测试:(未实现)......
  • Net7升级到Net8相关问题
    除了按照网上常规Net8升级步骤外,编译和运行都会发生一些异常和错误,代码兼容性根据提示倒是可以修改。倒是运行时错误,网上资料比较少,下面会持续登记升级过程中踩的坑:1. MediatR库升级到最新的12.2后,报错各种服务找不到,实际是没有DI实现:原来注册一般这么写:1services.AddMedia......
  • C#/.NET/.NET Core优秀项目和框架2024年2月简报
    前言公众号每月定期推广和分享的C#/.NET/.NETCore优秀项目和框架(每周至少会推荐两个优秀的项目和框架当然节假日除外),公众号推文中有项目和框架的介绍、功能特点、使用方式以及部分功能截图等(打不开或者打开GitHub很慢的同学可以优先查看公众号推文,文末一定会附带项目和框架源码......
  • .NET开源功能强大的串口调试工具
    前言今天大姚给大家分享一款.NET开源的、功能强大的串口调试工具:LLCOM。工具介绍LLCOM是一个.NET开源的、功能强大的串口调试工具。支持Lua自动化处理、串口调试、串口监听、串口曲线、TCP测试、MQTT测试、编码转换、乱码恢复等功能。功能列表收发日志清晰明了,可同时显示HEX......
  • Powercat 是 Netcat 的 PowerShell 版本
    Powercat是Netcat的PowerShell版本。支持Powershell版本2及更高版本。安装powercat是一个PowerShell函数。在执行之前,您需要先加载这个函数。您可以将以下命令之一放入您的PowerShell配置文件中,这样在PowerShell启动时就会自动加载powercat。从下载的.ps1文......
  • ASP.NET(C#)返回上一页(后退)代码
    转:ASP.NET(C#)返回上一页(后退)代码//方法一protectedvoidPage_Load(objectsender,EventArgse){    if(!IsPostBack)   {ViewState["BackUrl"]=Request.UrlReferrer.ToString();}}//////返回按钮点击事件///protectedvoidButton1_Click(object......
  • D - Diversity of Scores
    D-DiversityofScoreshttps://atcoder.jp/contests/abc343/tasks/abc343_d 思路准备两个map第一个存储,每个分数作为key,以及得此分数的运动员列表作为value这样,可以非常快速统计出某一时刻所有分数总数。第二个存储,每个运动员作为key,以及此运动员当前的分......