ABP vNext 框架功能模块 - 依赖注入和属性注入

news/2025/10/24 20:30:50/文章来源:https://www.cnblogs.com/tangge/p/19164181

一、依赖注入(Dependency Injection)

核心辅助类

  • IServiceCollection:扩展方法(如AddTransientAddScoped)。
  • DependencyAttribute:标记注入生命周期(Transient/Scoped/Singleton)。
  • IIocResolver:手动解析服务。
  • ITransientDependency/IScopedDependency/ISingletonDependency:标记接口,自动注册对应生命周期的服务(无需手动在模块中配置)。

在ABP框架的依赖注入(DI)系统中,这些类和接口用于管理服务的注册与解析,核心目标是简化依赖注入的配置,确保服务按预期的生命周期(瞬时、作用域、单例)工作。以下是具体示例和讲解:

1. IServiceCollection:服务注册的核心接口(配合扩展方法)

IServiceCollection是.NET依赖注入的标准接口,ABP通过扩展方法(如AddTransientAddScopedAddSingleton)简化服务注册,定义服务的类型和生命周期。

示例:手动注册服务

public class MyModule : AbpModule
{public override void ConfigureServices(ServiceConfigurationContext context){// 获取IServiceCollection实例var services = context.Services;// 1. 注册瞬时服务(每次请求创建新实例)services.AddTransient<IBookService, BookService>();// 2. 注册作用域服务(同一请求内共享实例)services.AddScoped<IAuthorRepository, AuthorRepository>();// 3. 注册单例服务(整个应用生命周期共享一个实例)services.AddSingleton<ILoggerProvider, CustomLoggerProvider>();// 4. 注册泛型服务(如仓储)services.AddScoped(typeof(IRepository<,>), typeof(EfCoreRepository<,>));}
}

讲解:

  • IServiceCollection是服务注册的“容器”,所有服务需通过它注册后才能被依赖注入系统识别。
  • 生命周期说明:
    • Transient:适合轻量级、无状态服务(如工具类),每次注入或解析时创建新实例。
    • Scoped:适合数据库上下文、仓储等,在一次HTTP请求内复用实例(避免频繁创建连接)。
    • Singleton:适合全局配置、缓存等,整个应用生命周期只创建一次实例。
  • ABP在模块的ConfigureServices方法中提供ServiceConfigurationContext,通过它可直接访问IServiceCollection

2. DependencyAttribute:通过特性标记服务生命周期

DependencyAttribute是ABP提供的特性,可直接标记在类上,指定服务的生命周期,无需手动在IServiceCollection中注册(框架会自动扫描并注册)。

示例:用特性标记服务生命周期

using Volo.Abp.DependencyInjection;// 标记为瞬时服务(等价于AddTransient)
[Dependency(ServiceLifetime.Transient)]
public class BookService : IBookService
{// 实现...
}// 标记为作用域服务,且允许被替换(便于测试时Mock)
[Dependency(ServiceLifetime.Scoped, ReplaceServices = true)]
public class AuthorRepository : IAuthorRepository
{// 实现...
}// 标记为单例服务,且自动注册其接口
[Dependency(ServiceLifetime.Singleton, ImplementInterfaces = true)]
public class GlobalConfigService : IGlobalConfigService
{// 实现...
}

讲解:

  • 自动注册:标记[Dependency]后,ABP会在模块初始化时自动扫描并注册该类,无需在IServiceCollection中手动调用AddXXX

  • 参数说明

    • ServiceLifetime:指定生命周期(Transient/Scoped/Singleton)。
    • ReplaceServices:是否替换已注册的同类型服务(默认false,设为true可覆盖框架默认实现)。
    • ImplementInterfaces:是否自动注册类实现的所有接口(默认false,设为true后,注入接口时会返回该类实例)。

3. IIocResolver:手动解析服务(非构造函数注入场景)

IIocResolver是ABP提供的服务解析器,用于在无法通过构造函数注入的场景(如静态方法、动态代码)中手动获取服务实例,同时确保服务正确释放。

示例:手动解析服务

using Volo.Abp.DependencyInjection;public class BookManager : ITransientDependency
{private readonly IIocResolver _iocResolver;// 构造函数注入IIocResolverpublic BookManager(IIocResolver iocResolver){_iocResolver = iocResolver;}public void ProcessBook(Guid bookId){// 1. 解析瞬时服务(使用后需手动释放)using (var bookService = _iocResolver.ResolveAsDisposable<IBookService>()){var book = bookService.Object.GetById(bookId);// 处理书籍...}// 2. 解析作用域服务(在当前作用域内复用)var authorRepo = _iocResolver.Resolve<IAuthorRepository>();var author = authorRepo.GetByBookId(bookId);// 3. 解析单例服务(全局唯一实例,无需释放)var configService = _iocResolver.Resolve<IGlobalConfigService>();var maxBookCount = configService.GetMaxBookCount();}
}

讲解:

  • ResolveAsDisposable:用于解析TransientScoped服务,返回Disposable对象,通过using语句确保服务使用后自动释放(避免内存泄漏)。
  • Resolve:直接解析服务,适用于单例服务(无需释放)或明确知道服务生命周期的场景(需手动管理释放)。
  • 注意:尽量优先使用构造函数注入,仅在必要时使用IIocResolver(如动态生成的代码、静态方法)。

4. ITransientDependency/IScopedDependency/ISingletonDependency:标记接口自动注册

这三个接口是ABP提供的“标记接口”,无需指定特性或手动注册,只需让服务类实现对应接口,框架会自动按接口类型注册服务生命周期。

示例:通过接口标记生命周期

using Volo.Abp.DependencyInjection;// 实现ITransientDependency:自动注册为瞬时服务
public class BookService : IBookService, ITransientDependency
{// 实现...
}// 实现IScopedDependency:自动注册为作用域服务
public class AuthorRepository : IAuthorRepository, IScopedDependency
{// 实现...
}// 实现ISingletonDependency:自动注册为单例服务
public class GlobalConfigService : IGlobalConfigService, ISingletonDependency
{// 实现...
}

讲解:

  • 零配置注册:只需实现接口,无需其他代码,ABP会在模块扫描时自动注册,大幅简化配置。

  • 接口作用

    :这三个接口本身无任何方法,仅作为“标记”告知框架服务的生命周期,等价于:

    • ITransientDependency[Dependency(ServiceLifetime.Transient)]
    • IScopedDependency[Dependency(ServiceLifetime.Scoped)]
    • ISingletonDependency[Dependency(ServiceLifetime.Singleton)]
  • 适用场景:适合大多数常规服务,推荐优先使用(比DependencyAttribute更简洁)。

5. 总结:服务注册方式的选择

  1. 简单场景:优先使用ITransientDependency等标记接口(最简洁,零配置)。
  2. 需要自定义:使用DependencyAttribute(支持替换服务、注册接口等高级配置)。
  3. 批量或泛型服务:使用IServiceCollection的扩展方法(如泛型仓储、第三方服务)。
  4. 手动解析:通过IIocResolver(仅在构造函数注入不可行时使用)。

这些工具共同构成了ABP灵活的依赖注入系统,既简化了常规配置,又支持复杂场景的自定义需求。

二. 属性注入(Property Injection)

核心辅助类

  • [Inject]:标记属性为注入点(需配合IIocResolver或框架自动注入)。

在ABP框架中,[Inject]特性用于标记类的属性作为属性注入点,允许依赖注入系统自动为该属性赋值,而无需通过构造函数传递依赖。这在某些场景(如基类、第三方库类)中非常实用,因为这些类可能无法通过构造函数注入依赖。

[Inject]特性的使用示例

示例1:基础属性注入(框架自动注入)

using Volo.Abp.DependencyInjection;// 标记类为依赖注入服务(需配合生命周期接口或特性)
public class BookService : ITransientDependency
{// 用[Inject]标记属性,框架会自动注入ILogger实例[Inject]public ILogger<BookService> Logger { get; set; }public void DoWork(){// 使用注入的LoggerLogger.LogInformation("BookService is working...");}
}

示例2:在基类中使用属性注入

// 基类(无法通过构造函数注入,因为子类可能有不同构造函数)
public abstract class BaseService
{// 基类需要的依赖通过属性注入[Inject]protected IStringLocalizer<MyAppResource> Localizer { get; set; }public string GetLocalizedMessage(string key){return Localizer[key];}
}// 子类继承基类,自动获得Localizer的注入
public class BookService : BaseService, ITransientDependency
{public void ShowMessage(){// 直接使用基类中注入的Localizervar message = GetLocalizedMessage("BookCreated");Console.WriteLine(message);}
}

示例3:配合IIocResolver手动触发注入

如果类未被依赖注入系统管理(如手动new创建的实例),可通过IIocResolver手动触发属性注入:

public class MyNonManagedClass
{[Inject]public IBookService BookService { get; set; }public void DoSomething(){// 如果未触发注入,BookService可能为nullBookService?.CreateBook(new BookDto());}
}// 在其他服务中手动创建实例并触发注入
public class TestService : ITransientDependency
{private readonly IIocResolver _iocResolver;public TestService(IIocResolver iocResolver){_iocResolver = iocResolver;}public void Test(){// 手动创建未被DI管理的实例var myClass = new MyNonManagedClass();// 通过IIocResolver触发属性注入_iocResolver.InjectProperties(myClass);// 此时BookService已被注入,可安全使用myClass.DoSomething();}
}

核心讲解

  1. 适用场景
    • 基类共享依赖:当多个子类继承同一个基类,且基类需要依赖时,属性注入可避免每个子类在构造函数中重复传递依赖。
    • 无法修改构造函数的类:如第三方库中的类、自动生成的代码,无法添加构造函数参数,此时属性注入是唯一选择。
    • 可选依赖:某些依赖不是必须的(允许为null),属性注入比构造函数注入更灵活(构造函数参数通常是必须的)。
  2. 与构造函数注入的区别
    • 构造函数注入:依赖在对象创建时必须提供,确保对象实例化后即可正常使用(无null风险),是ABP推荐的主要注入方式。
    • 属性注入:依赖在对象创建后由框架自动赋值(或手动触发),存在未注入时为null的风险,适合非核心依赖。
  3. 注意事项
    • 必须配合依赖注入容器:只有被ABP依赖注入系统管理的类(如实现了ITransientDependency的类),框架才会自动执行属性注入。手动new的实例需通过IIocResolver.InjectProperties()手动触发。
    • 避免过度使用:属性注入可能导致依赖关系不明显(不如构造函数参数直观),建议优先使用构造函数注入,仅在必要时使用属性注入。
    • 可空检查:使用属性注入的依赖可能为null,需在代码中添加空值检查(如BookService?.CreateBook(...)),或通过[Required]特性要求必须注入(框架会在注入失败时抛异常)。

总结

[Inject]特性是ABP依赖注入系统的补充,用于解决构造函数注入不适用的场景。它通过标记属性为注入点,让框架或开发者手动为其赋值,平衡了灵活性和易用性。但需注意其潜在的null风险,合理选择注入方式。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/945645.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SAP维护汇率的关键Tcode

Tcode: OB08 维护汇率Tcode:OBBS 维护汇率的折算比率☆ No matter how much you change, you still have to pay the price for the things youve done.

幂函数

观察幂函数图像结论: 所有的幂函数都过1,1点,幂函数在第一象限必有图像。 a为负数时,不过0,0点,其余都有0,0点。 一、画函数用结论,a<0,单调递减,a>0,单调递增。 二、0<a<1之间,增的缓,a>1,…

ABP vNext 框架功能模块 - 动态API(Dynamic API)[RemoteServiceAttribute | DynamicApiControllerBuilder]

动态API(Dynamic API) 核心辅助类:DynamicApiControllerBuilder:动态生成API控制器。 RemoteServiceAttribute:标记类/方法为远程服务(自动暴露API)。在ABP框架中,DynamicApiControllerBuilder和RemoteService…

第4天(中等题 滑动窗口、哈希表)

打卡第四天 两道中等题哈希表记录元素频率:哈希表程序表示:滑动窗口+哈希表优化算法耗时≈一小时 明天继续 小tips:不小心删除可以用 Ctrl+Z 撤回刚刚消除的代码/文字

ABP vNext 框架功能模块 - 动态API(Dynamic API)

** 动态API(Dynamic API)** 核心辅助类:DynamicApiControllerBuilder:动态生成API控制器。 RemoteServiceAttribute:标记类/方法为远程服务(自动暴露API)。在ABP框架中,DynamicApiControllerBuilder和RemoteSe…

ABP vNext 框架功能模块 - 模块化(Modularity)

模块化(Modularity) 核心辅助类:AbpModule:所有模块的基类,定义模块生命周期方法。 DependsOnAttribute:声明模块依赖关系。 ModuleInitializer:模块初始化器(自动生成)。 IModuleContainer:模块容器,用于运…

ABP vNext 框架功能模块

以下是ABP框架中各核心功能的辅助类及示例说明,涵盖模块化、依赖注入、ORM集成等关键特性: 一. 模块化(Modularity) 核心辅助类:AbpModule:所有模块的基类,定义模块生命周期方法。 DependsOnAttribute:声明模块…

题解:P14299 [JOI2023 预选赛 R2] 填充 / Painting

\(\displaystyle \large {题目传送门}\) 题面 给定一个一个 H*W 的矩形 , 每个坐标上有一个颜色 , 上下左右相邻的同颜色节点可以形成连通块 。 你可以对任意一个连通块 , 进行一次并仅有一次的染色 , 求新形成的连…

Devolutions Server权限提升漏洞分析与修复指南

本文详细分析了CVE-2025-11957漏洞,该漏洞存在于Devolutions Server 2025.2.12.0及更早版本中,由于临时访问工作流程的授权机制存在缺陷,允许经过身份验证的基本用户通过精心构造的API请求自我批准或批准其他用户的…

AI股票预测分析报告 - 2025年10月24日 - 20:08:50

AI股票预测分析报告 - 2025年10月24日body { font-family: "Microsoft YaHei", "Segoe UI", Tahoma, Geneva, Verdana, sans-serif; line-height: 1.6; color: rgba(51, 51, 51, 1); max-width: 1…

在 Astro 博客中优雅使用 51.la 统计数据

在 Astro 博客中使用 51.la 免费流量统计,通过解析 widget JS 自行渲染访问数据,既保留统计功能,又可自定义展示,让你直观了解博客访客情况作为老牌网站流量统计服务商,51.la 提供每月高达 1000 万次的免费统计额…

申威服务器安装Java11(swjdk-11u-9.ky10.sw_64.rpm)详细操作步骤(附安装包)

申威服务器安装Java11(swjdk-11u-9.ky10.sw_64.rpm)详细操作步骤(附安装包)​这是申威架构(国产芯片,常见于Kylin V10等国产系统)专用的 ​Java 11 版本(RPM安装包)​,包名为 java-11.0.7-swjdk-11u-9.ky10.…

str.endswith() 类似的方法

在Python中,与str.endswith()类似的方法(主要涉及字符串的开头/结尾检查、子串搜索等)有很多,以下是核心方法及其功能对比: 1. 开头检查:str.startswith()功能:检查字符串是否以指定前缀开头,返回True/False。…

深度剖析OpenHarmony AI Engine:开发板端侧大模型推理插件机制全链路拆解 - 实践

深度剖析OpenHarmony AI Engine:开发板端侧大模型推理插件机制全链路拆解 - 实践pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font…

Linux下的拼音输入法 (3)

此贴简介libgooglepinyin-0.1.2,刚看了几分钟(持续更新中): data/下: 730 2012年 2月 3日 CMakeLists.txt227 2012年 2月 3日 googlepinyin.pc.in3.5M 2012年 2月 3日 rawdict_utf16_65105_freq.be.txt3.5M 2012年…

P2606 [ZJOI2010] 排列计数 分析

题目概述 题目链接:https://www.luogu.com.cn/problem/P2606。 称一个 \(1 \sim n\) 的排列 \(p_1,p_2, \dots ,p_n\) 是 Magic 的,当且仅当 \[\forall i \in [2,n],p_i > p_{\lfloor i/2 \rfloor} \]计算 \(1 \s…

实用指南:MacOS - Clang使用bits/stdc++.h - 非官方(竞赛用) - 通用方法

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

cgroup

cgroupcgroup v1使用流程: mount -t tmpfs cgroup_root /sys/fs/cgroup mkdir -p /sys/fs/cgroup/cpu mkdir -p /sys/fs/cgroup/memory mount -t cgroup -o cpu none /sys/fs/cgroup/cpu mount -t cgroup -o memory n…

设计模式:代码界的 “光之巨人” 养成指南(附 C++ 实战)

参考 https://bbs.huaweicloud.com/blogs/397606 https://refactoring.guru/design-patterns/catalog 一、概述 1.1、什么是设计模式 官方定义说得有点绕:“一套被反复使用、多数人知晓、分类编目的代码设计经验总结”…