.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 ...
随机推荐
- 扯淡的DevOps,我们开发根本不想做运维!
引言 最初考虑引用" DevOps 已死,平台工程才是未来"作为标题,但这样的表达可能太过于绝对.最终,决定用了"扯淡的"这个词来描述 DevOps,但这并不是 ...
- .net core微服务之网关
网关: 一:apisix doc:https://apisix.apache.org/zh/docs/apisix/getting-started/README/ github:https://git ...
- 发布Npm包到GitHub Packages
发布Npm包到GitHub Packages Github集成了GitHub Packages功能,目前提供了Npm.Docker.Maven.NuGet.RubyGems的包管理工具,可以通过Git ...
- oracle中约束(constraints)是如何影响查询计划的
原文: http://www.oracle.com/technetwork/issue-archive/2009/09-may/o39asktom-096149.html oracle中约束(cons ...
- letcode-括号生成
递归大法,空间换时间 就是记录左右括号数,一旦右括号数大于左括号数,退出. 当左右括号数相等,且等于n则为合法解. 使用char数组取代StringBuilder可以减少内存使用,这样每次进行回溯时不 ...
- windows 程序启动后挂到后台
开发中遇到一个问题,程序启动后,并没有出现在前台,而是自动挂到后台,程序处于卡死状态,基本任何模块都没加载进来. 后面排查发现跟一个功能的第三方 dll 有关系,在那个 dll 加载时导致程序卡死,因 ...
- 麒麟系统开发笔记(十一):在国产麒麟系统上使用gdb定位崩溃异常方法流程进阶定位代码行数及专项测试Demo
前言 上一篇,通过研究,可以定位到函数,本篇进一步优化,没有行数,程序较为复杂的时候,就无法定位,所以进一步定位. 本篇做了qBreakpad的研究,但是没有成功,过程也还是填出来,后来突然注意 ...
- Hi3516开发笔记(八):Hi3516虚拟机交叉开发环境搭建之配置QtCreator开发交叉编译环境
海思开发专栏 上一篇:<Hi3516开发笔记(七):Hi3516虚拟机交叉开发环境搭建之交叉编译Qt>下一篇:<Hi3516开发笔记(九):在QtCreator开发环境中引入海思sd ...
- docker部署fastdfs并在Django中集成
拉取Fastdfs镜像 docker pull delron/fastdfs 构建Tracker容器 是在Linux环境下,使用docker镜像构建tracker容器,用于启动跟踪服务器,起到调度的作 ...
- 框架和MVC架构
网络框架及MVC架构 网络框架 所谓网络框架是指这样的一组Python包,它能够使开发者专注于网站应用业务逻辑的开发,而无须处理网络应用底层的协议.线程.进程等方面.这样能大大提高开发者的工作效率,同 ...