.Net依赖注入神器Scrutor(下)
前言
上一篇文章我们讲到了Scrutor第一个核心功能Scanning,本文讲解的是Scrutor第二个核心的功能Decoration 装饰器模式在依赖注入中的使用。
- 装饰器模式允许您向现有服务类中添加新功能,而无需改变其结构
Install-Package Scrutor
本文的完整源代码在文末
Decoration 依赖注入代理模式
首先首先一个 获取 User 的服务
定义 User 类
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public string? Email { get; set; }
}
定义接口和实现
public interface IUserService
{
List<User> GetAllUsers();
}
public class UserService : IUserService
{
public List<User> GetAllUsers()
{
Console.WriteLine("GetAllUsers方法被调用~");
List<User> users = [
new User(){
Id= 1,
Name="张三",
Age=18,
Email="zhangsan@163.com"
},
new User(){
Id= 2,
Name="李四",
Age=19,
Email="lisi@163.com"
},
];
return users!;
}
}
现在有了我们的获取全部用户的服务了,需求是在不破坏当前类的添加装饰器模式,为 GetAllUsers 接口添加缓存。
创建装饰器类
public class UserDecorationService(IUserService userService, IMemoryCache cache) : IUserService
{
public List<User> GetAllUsers()
{
Console.WriteLine("GetAllUsers代理方法被调用~");
return cache.GetOrCreate("allUser", cacheEntry =>
{
cacheEntry.SetAbsoluteExpiration(
TimeSpan.FromMinutes(5));
var allUsers = userService.GetAllUsers();
return allUsers ?? [];
})!;
}
}
DI 容器添加服务
builder.Services.AddTransient<IUserService, UserService>();
builder.Services.AddMemoryCache();
builder.Services.Decorate<IUserService, UserDecorationService>();
创建接口测试一下
app.MapGet("/GetAllUsers", ([FromServices] IUserService userService) => userService.GetAllUsers()).WithSummary("获取全部用户接口");
调用第一次
GetAllUsers代理方法被调用~
GetAllUsers方法被调用~
第二次调用
GetAllUsers代理方法被调用~
可以看出第一次没缓存装饰器类和我们 UserService 都调用了,第二次因为只有了缓存所以只调用了装饰器类,可以看出我们的装饰器模式生效了。
依赖注入装饰器底层核心实现
/// <summary>
/// Decorates all registered services using the specified <paramref name="strategy"/>.
/// </summary>
/// <param name="services">The services to add to.</param>
/// <param name="strategy">The strategy for decorating services.</param>
public static bool TryDecorate(this IServiceCollection services, DecorationStrategy strategy)
{
Preconditions.NotNull(services, nameof(services));
Preconditions.NotNull(strategy, nameof(strategy));
var decorated = false;
for (var i = services.Count - 1; i >= 0; i--)
{
var serviceDescriptor = services[i];
if (IsDecorated(serviceDescriptor) || !strategy.CanDecorate(serviceDescriptor))
{
continue;
}
var serviceKey = GetDecoratorKey(serviceDescriptor);
if (serviceKey is null)
{
return false;
}
// Insert decorated
services.Add(serviceDescriptor.WithServiceKey(serviceKey));
// Replace decorator
services[i] = serviceDescriptor.WithImplementationFactory(strategy.CreateDecorator(serviceDescriptor.ServiceType, serviceKey));
decorated = true;
}
return decorated;
}
这个代码是在 dotNet8 的环境下编译的,可以看出做了几件事:
第一 IServiceCollection 集合倒序遍历,找到符合条件的ServiceType
核心代码一
// Insert decorated
services.Add(serviceDescriptor.WithServiceKey(serviceKey));
将原先的ServiceDescription作为基础,添加了ServiceKey后再进行添加操作,新的服务描述符会被添加到服务集合的末尾,
核心代码二
// Replace decorator
services[i] = serviceDescriptor.WithImplementationFactory(strategy.CreateDecorator(serviceDescriptor.ServiceType, serviceKey));
这一步是将原有的服务描述符替换为一个新的服务描述符,新的服务描述符使用装饰器工厂方法创建,实现了服务的装饰功能。
用的时候
app.MapGet("/GetAllUsers", ([FromServices] IUserService userService) => userService.GetAllUsers()).WithSummary("获取全部用户接口");
这样就可以获取到装饰器类提供服务,之前看到services.Add(serviceDescriptor.WithServiceKey(serviceKey));在代码的最后添加了一个服务,那 IOC 获取的时候肯定是从后面优先获取,这地方用了 dotNet8 的键控依赖注入(KeyedService),以 ServiceType 获取服务只会获取到我们提供的装饰器实例,这一手简直是神来之笔 。
最后
Scrutor的装饰器模式可以用于动态地给依赖注入的实例添加额外职责,实现动态增加和撤销功能,而无需改变原有对象结构。可以在不影响其他对象的情况下,以透明且动态的方式给对象添加新功能,实现系统的灵活扩展和维护。
本文完整源代码
.Net依赖注入神器Scrutor(下)的更多相关文章
- 【半小时大话.net依赖注入】(下)详解AutoFac+实战Mvc、Api以及.NET Core的依赖注入
系列目录 上|理论基础+实战控制台程序实现AutoFac注入 下|详解AutoFac+实战Mvc.Api以及.NET Core的依赖注入 前言 本来计划是五篇文章的,每章发个半小时随便翻翻就能懂,但是 ...
- <Pro .NET MVC4> 三大工具之依赖注入神器——Ninject
这篇内容是对<Pro .NET MVC4>一书中关于Ninject介绍的总结. Ninject是.NET MVC的一款开源的依赖注入工具. 使用场景:当MVC项目中使用了依赖注入技术来给程 ...
- 从零开始,搭建博客系统MVC5+EF6搭建框架(2),测试添加数据、集成Autofac依赖注入
一.测试仓储层.业务层是否能实现对数据库表的操作 1.创建IsysUserInfoRepository接口来继承IBaseRepository父接口 namespace Wchl.WMBlog.IRe ...
- Spring的核心机制——依赖注入(Dependency Inject)
Spring不仅提供对象,还提供对象的属性值,而不是由使用该对象的程序所提供的. Java应用是由一些相互协作的对象所组成的,在Spring中这种相互协作的关系就叫依赖关系. 如果A组件调用了B组件的 ...
- (五)Angularjs - 依赖注入
如何找到API? AngularJS提供了一些功能的封装,但是当你试图通过全局对象angular去 访问这些功能时,却发现与以往遇到的库大不相同. 比如,AngularJS暴露了一个全局对象:angu ...
- AngularJS应用开发思维之3:依赖注入
找不到的API? AngularJS提供了一些功能的封装,但是当你试图通过全局对象angular去 访问这些功能时,却发现与以往遇到的库大不相同. $http 比如,在jQuery中,我们知道它的AP ...
- 基于ABP模块组件与依赖注入组件的项目插件开发
注意,阅读本文,需要先阅读以下两篇文章,并且对依赖注入有一定的基础. 模块系统:http://www.cnblogs.com/mienreal/p/4537522.html 依赖注入:http://w ...
- angular2的依赖注入
更好阅读体验,请看原文 在读这篇文章之前,你要先了解一下什么是依赖注入,网上关于这个的解释很多,大家可以自行Google. 我们这一篇文章还是以QuickStart项目为基础,从头开始讲解怎么在Ang ...
- Spring的核心机制——依赖注入(Dependency Inject)
Spring不仅提供对象,还提供对象的属性值,而不是由使用该对象的程序所提供的. Java应用是由一些相互协作的对象所组成的,在Spring中这种相互协作的关系就叫依赖关系. 如果A组件调用了B组件的 ...
- SignalR中的依赖注入
什么是依赖注入? 如果你已经熟悉依赖注入可以跳过此节. 依赖注入 (DI) 模式下,对象并不为自身的依赖负责. 下边的例子是一个主动 DI. 假设你有个对象需要消息日志.你可能定义了一个日志接口: C ...
随机推荐
- TStringList的IndexOfName
IndexOfName这个方法用着很好,记录下,以后留意下 上个例子: procedure TForm1.Button1Click(Sender: TObject); var MyList: TStr ...
- RDS for MySQL并发性能测试
最近由于工作需要,需要对阿里云数据库-RDS for MySQL进行性能测试,通过MySQL自带的mysqlslap工具可以进行并发性能测试,但是输出显示总感觉有问题,所以就萌生想法自己开发代码通过J ...
- Resharper 和 Rider 的奇淫技巧,你知道多少?
Resharper 和 Rider 的奇淫技巧,你知道多少? .NET 开发中最令人印象深刻的生产力工具之一是ReSharper.每次发布时,我都对它的功能感到震惊.不要误会我的意思,我喜欢 Visu ...
- VMware全版本下载工具
有很多小伙伴想下载适合自己的虚拟机版本,但是官网全是英文看不懂 百度找的还怕带病毒 这里栀煜单独制作了个工具,内置vm9 10 11 12 14 15 16 17版本的虚拟机下载地址,都是官方版 不是 ...
- Ubuntu 22.04 Samba 安装和配置
安装 安装 sudo apt install samba 检查服务状态 systemctl status smbd --no-pager -l 检查是否启用(开机自启动) systemctl is-e ...
- Rtmp 开发学习
参考文章:视频传输协议详解(RTMP.RTSP.HLS) RTMP--Real Time Messaging Protocol(实时消息传输协议) RTMP 是由 Adobe 公司提出的,在互联网 T ...
- 泛型类Generic注解
在 Python 的 typing 模块中,Generic 是一个泛型类,用于创建参数化的类和函数,以便支持不同类型的参数.它允许你定义具有类型参数的类,这些类型参数在实例化时才确定.这样,你可以在不 ...
- 06-Redis系列之-哨兵(Redis-Sentinel)和集群详解和搭建
主从架构高可用 主从架构存在的问题 主从复制,主节点发生故障,需要做故障转移.(可以手动转移:让其中一个slave变成master) 主从复制,只有主写数据,所以写能力和存储能力有限 总结:redis ...
- vue 前端自动打开文件地址进行下载
最近在做异步导出的功能,导出的过程中前端另外启动一个查询导出进度的线程接口.如果导出完成后,把生成的文件上传到服务器,返回给前端一个文件的下载地址:前端自动打开这个地址进行跳转下载. 有两种方式 1. ...
- Java11改进的垃圾回收器
传统的C/C++等编程语言,需要程序员负责回收已经分配的内存.显示进行垃圾回收是一件比较困难的事情,因为程序员并不总是知道内存应该何时被释放.如果一些分配出去的内存得不及时回收,就会引起系统运行速度下 ...