深入了解Nest的模块Module在上文Provider中提到,将某一类特定功能最终包装到一个模块(Module)中,每

@Module装饰器接受一个对象参数,在Nest源码中是ModuleMetadata接口,它有四个字段,且均是数组类型,分别是:

通过以上四种类型的设定,Nest的IoC才能够准确识别需要组装(注入和被注入)各种依赖关系,同时实现一定程度的共享。

SOLID指面向对象编程中的五项基本原则。应用这些原则,可以提升程序的可维护行和扩展性,同时也让大规模协作开发变得可能。表格源自WiKi:

模块的设计遵循SOLID原则。另外,在Nest中:一组功能也会被归类到一个文件夹中,同时体现在程序文件名的前缀上。

nestgmouser内容如下:

@Module({controllers:[UserController],providers:[AppService],})exportclassUserModule{}还需要修改app.module,引入user.module

@Module({imports:[UserModule],controllers:[AppController],providers:[AppService],})exportclassAppModule{}运行项目,然后依次执行下面的代码,查看输出:

npmrunstart:devcurl--location--requestGET'localhost:3000/setstr=Hi~'#donecurl--location--requestGET'localhost:3000/get'#Hi~curl--location--requestGET'localhost:3000/user/get'#curl--location--requestGET'localhost:3000/user/setstr=HiUser~'#donecurl--location--requestGET'localhost:3000/user/get'#HiUser~curl--location--requestGET'localhost:3000/get'#Hi~根据这个结果,不难推断出,AppService在AppModule和UserModule中是两个独立存在的实例。也许这并不符合我们的开发本意,而是需要使用一个实例。这就是Nest的模块共享的实质意义。

我们只需要将UserModule添加一行export[AppServie],将AppModule中的providers:[AppService]删去(反之亦然),即可实现功能的共享。然后再次执行上面的检查代码,看看输出结果。

先前在Provider章节中提到,Provider是一个比较宽泛的概念,不仅局限于Service类型,实际上任何一个类、值乃至一个接口,都可以视作一个Provider。在调用时也可以使调用时也可以用参数装饰器@Inject()来修饰后面的参数需要什么样的依赖。例如:

exportclassAppService{constructor(@Inject('MethodOptions')privateoption:MethodOptions){}}在应用Provider时,我们说一下Provider的几种类型,查看源代码:

在上级模块引入模块时,可以调用模块的静态方法,以获得一个DynamicModule对象,例如:

为了让源代码够简单,在最小的项目基础上只增加了User,两者在层级上有上下级关系,但两者关于调用Provider是一样的。有兴趣的同学可以在增加一个类型(例如Customer)装配在App的下面。用最简单的内容来举例,抽象类和两个实现(一共三个文件):

///src/common/common.abstract.tsexportabstractclassAbstractDBCommonService{setPrefix(value:string){}getPrefix():string{return'abstract';}}///src/common/user.db.service.tsimport{AbstractDBCommonService}from'./common.abstract';exportclassUserDBServiceimplementsAbstractDBCommonService{private_prefix:string='user';setPrefix(value:string){this._prefix=value;}getPrefix():string{returnthis._prefix;}}///src/common/app.db.service.tsimport{AbstractDBCommonService}from'./common.abstract';exportclassAppDBServiceimplementsAbstractDBCommonService{private_prefix:string='app';setPrefix(value:string){this._prefix=value;}getPrefix():string{returnthis._prefix;}}添加User和App对DB.Service的依赖,UserController的代码与AppController代码较为相似,两者不需要关心具体实现了什么:

///src/user/user.controller.tsimport{Controller,Get,Query}from'@nestjs/common';import{AppService}from'src/app.service';import{AbstractDBCommonService}from'src/common/common.abstract';@Controller('user')exportclassUserController{constructor(privatereadonlyappService:AppService,privatecommonService:AbstractDBCommonService,){}@Get('/')hello():string{returnthis.commonService.getPrefix()+this.appService.getHello();}}上面的代码中,构造函数需要有两个注入,AppSerivce和AbstractDBCommonService,我们可以将这两个Provider视作为某一类服务所共同需要的支持,在hello方法中,输出是这两个Service功能的整合。AppController文件与之基本保持一致。动态模块CommonModule的代码如下:

///src/common/common.module.tsimport{DynamicModule,Inject,Module}from'@nestjs/common';import{AppDBService}from'./app.db.service';import{AbstractDBCommonService}from'./common.abstract';import{UserDBService}from'./user.db.service';constWarehouse={AppDBService,UserDBService};@Module({})exportclassCommonModule{staticLoadByClass(kind:string):DynamicModule{constprovider={provide:AbstractDBCommonService,useClass:Warehouse[kind],};return{module:CommonModule,providers:[provider],exports:[provider],};}}然后是UserModule和AppModule

///src/user/user.module.tsimport{Module}from'@nestjs/common';import{AppService}from'../app.service';import{UserController}from'./user.controller';import{CommonModule}from'src/common/common.module';@Module({imports:[CommonModule.LoadByClass('UserDBService')],controllers:[UserController],providers:[AppService],})exportclassUserModule{}///src/app.module.tsimport{Module}from'@nestjs/common';import{AppController}from'./app.controller';import{AppService}from'./app.service';import{UserModule}from'./user/user.module';import{CommonModule}from'./common/common.module';@Module({imports:[UserModule,CommonModule.LoadByClass('AppDBService')],controllers:[AppController],providers:[AppService],})exportclassAppModule{}运行代码得到结果:

providers:[{provider:SomeService,useClass:SomeService}]值型的Provider官方的案例以及网上大多数的案例都是以值类型的Provider来演示的。基本原理是:不同的环境以确定不同的“值”,这个值是加载不同的配置文件(名)。

假设CommonService为UserController和AppController提供服务,另外,为了方便,需要安装一个dotenv组件(npminstall--savedotenv)。

///src/common/common.service.tsimport{Inject,Injectable}from'@nestjs/common';import*asdotenvfrom'dotenv';import*asfsfrom'fs';@Injectable()exportclassCommonService{privatereadonlyenv;constructor(@Inject('file')file:string){this.env=dotenv.parse(fs.readFileSync(file));}getPrefix(){returnthis.env['PREFIX'];}}接着定义两个配置文件/config/app.env和/config/user.env。注意,配置文件不能放在src目录下,因为ts文件会被编译为js文件,并且放在dist目录中执行,如果放在源代码目录中又没有利用webpack进行特定的打包时,就会发生无法找到文件的异常。文件内容及其简单:

PREFIX=APP我们将CommonModule文件稍加修改,另外用一个静态的方法LoadByValue:

///src/common/common.module.tsimport{DynamicModule,Inject,Module}from'@nestjs/common';import*aspathfrom'path';import{CommonService}from'./common.service';@Module({})exportclassCommonModule{staticLoadByValue(file:string):DynamicModule{constenvFile=path.resolve(__dirname,'../../config',file);return{module:CommonModule,providers:[{provide:'file',useValue:envFile},CommonService],exports:[CommonService],};}}接着将UserModule和AddModule的引用方式改为imports:[CommonModule.LoadENV('user.env')],以及相应的AppController和UserController的构造函数依赖:privatereadonlycommonService:CommonService。运行代码的结果:

///src/common/common.module.tsimport{DynamicModule,Inject,Module}from'@nestjs/common';import{AppDBService}from'./app.db.service';import{UserDBService}from'./user.db.service';constWarehouse={UserDBService,AppDBService};@Module({})exportclassCommonModule{staticLoadByFactory(kind:string):DynamicModule{constprovide={provide:kind,useFactory:()=>{returnnewWarehouse[kind]();},};return{module:CommonModule,providers:[provide],exports:[provide],};}}UserModule和AppModule改动

///src/app.module.tsimport{Module}from'@nestjs/common';import{AppController}from'./app.controller';import{AppService}from'./app.service';import{UserModule}from'./user/user.module';import{CommonModule}from'./common/common.module';@Module({imports:[UserModule,CommonModule.LoadByFactory('AppDBService')],controllers:[AppController],providers:[AppService],})exportclassAppModule{}UserController和AppController的改动。注意,第9和10行是等效的。

///src/app.controller.tsimport{Controller,Get,Inject,Put,Query}from'@nestjs/common';import{AppService}from'./app.service';@Controller()exportclassAppController{constructor(privatereadonlyappService:AppService,@Inject('AppDBService')privatereadonlycommonService,//等效privatereadonlycommonService:AppDBService,){}@Get()getHello():string{returnthis.commonService.Prefix+this.appService.getHello();}}被依赖的类型如果是同一个(将上文中App和User调整为同一个依赖项),你会发现他们共享了同一个实例。

@Module({})exportclassCommonModule{staticLoadByFactory(kind:string):DynamicModule{constprovide={provide:kind,useFactory:(a:A,b:B)=>{console.log(a,b);//->A{}B{}returnnewWarehouse[kind]();},inject:[A,B],};return{module:CommonModule,//imports:[TestModule],providers:[A,B,provide],exports:[provide],};}}注意,被依赖的A和B必须是作为Provider来看待,也就是说,要么在providers中,也可以是注册在其他module中的共享providers并导入(imports)在当前模块中。Nest会自动将对象实力化,并送入useFactory()中。

当使用useClass的动态模块组装模块时,每个模块都会实例化类并且私有使用。如果这个类需要被共享使用(单例),例如一个配置文件,那么就可以使用这个方式。需要注意的是:因为是一个别名,实际上并不存在于实际的代码中,所以在依赖方的代码中不能依靠类型限制来自动完成注入,而是利用@Inject()装饰器。

///src/app.controller.tsimport{Controller,Get,Inject,Put,Query}from'@nestjs/common';import{AppService}from'./app.service';@Controller()exportclassAppController{constructor(privatereadonlyappService:AppService,@Inject('AppDBService')privatereadonlycommonService,){}}同理UserController。CommonModule改为:

import{DynamicModule,Module}from'@nestjs/common';import{AbstractDBCommonService}from'./common.abstract';@Module({})exportclassCommonModule{staticloadByExisting():DynamicModule{constuserAliasConfigFile={provide:'UserDBService',useExisting:AbstractDBCommonService,};constappAliasConfigFile={provide:'AppDBService',useExisting:AbstractDBCommonService,};return{module:CommonModule,providers:[AbstractDBCommonService,userAliasConfigFile,appAliasConfigFile,],exports:[AbstractDBCommonService,userAliasConfigFile,appAliasConfigFile,],};}}执行测试程序可以发现,虽然是不同的注入项目,但最终依赖的AbstractDBCommonService是同一个实例。如果将*AliasConfigFile直接放在app.module.ts和user.module.ts的providers中,其实也是可以完成别名的依赖配置,但是两者使用的不同的实例。

以上动态模块根据接口主要分为四个不同的类别:

动态类同样是可以被输出共享(exports),导出需要使用于provider的provide字段关联。例如工厂模式中,定义一个{provide:'xxx',userFactory:()=>{...}},将其输出就是exports:['xxx'],其他同理。

在上文模块共享中提到过,Nest的策略遵循SOLID中的O,开闭原则:有限度的开放,所以一个模块除非是定义为输出共享,它才能被其他依赖方程序使用。假如某个模块几乎所有的地方都会被用到,那么可以利用@Global()装饰器,将你的模块定义为全局范围。如果是动态模块,那么在返回的DynamicModule中加入globa:true即可。

不论是@Global()静态模块还是global:true的动态模块,只需要且也必须注册一次,一般情况下可以放在根模块app.module.ts或者核心模块中即可。

THE END
1.solid原来有这么多用法腾讯云开发者社区作为形容词时,它可以表示:固体的:指物质的一种状态,具有确定的形状和体积,不容易流动,如“solid gold”(纯金)。坚硬的:指物体坚固、不易变形或破裂,如“solid wood”(实木)。无空隙的、非中空的:指物体内部没有空隙或空洞,如“solid wall”(实心墙)。实https://cloud.tencent.com/developer/news/1378478
2.solid是什么意思,solid中文翻译怎么读3325英语网的英语单词大全为大家提供solid是什么意思,solid的用法,solid词根词缀怎么读,含义,英汉双语例句等高效记单词的助记学习查询服务。https://3325.cn/dict/solid/
3.SimMechanics使用Matlab/SimMechanics仿真机械臂注:在建立Solid的frames之前需要先规划好整个机械臂的坐标系,这里我的坐标系建立是按照改进型DH参数来建立。 2.2 Rigid Transform模块 设置坐标系的旋转和平移,Standard Axis表示绕port B的坐标系的轴旋转平移变化得到的port F坐标系,None表示不平移或者不旋转。 https://blog.csdn.net/ndjasdn/article/details/109085843
4.SolidBrush类(System.Drawing)MicrosoftLearnColor customColor = Color.FromArgb(50, Color.Gray); SolidBrush shadowBrush = new SolidBrush(customColor); e.Graphics.FillRectangles(shadowBrush, new RectangleF[]{rectFToFill}); // Dispose of the brush. shadowBrush.Dispose(); } 注解https://msdn.microsoft.com/zh-cn/library/system.drawing.solidbrush.aspx
5.我国的民族类大学数量不多,拥有重点头衔的更屈指可数高校top世http://mwp.solidcycle.com.cn//P1P.html http://mw.chuao.com.cn//exo.html http://mw.jebely.net.cn//MV5.html http://www.cnbci.com.cn//QhZ.html http://www.0576sf.cn//U1Y.html http://www.cnbci.com.cn//fjz.html http://mwp.solidcycle.com.cn//OJl.html https://www.163.com/dy/article/JJR2T0FF0556B2U4.html
6.SOLID在剑桥基础英式英语词典中的解释及翻译SOLID的意思、解释及翻译:1. hard and firm without holes or spaces, and not liquid or gas: 2. strong and not easily broken…。了解更多。https://dictionary.cambridge.org/zhs/%E8%AF%8D%E5%85%B8/%E5%9F%BA%E7%A1%80%E8%8B%B1%E5%BC%8F%E8%8B%B1%E8%AF%AD/solid
7.一篇带给你架构师常用术语梳理SOLID原则包括以下五个: 1、单一职责原则(SRP) 表明一个类有且只有一个职责。一个类就像容器一样,它能添加任意数量的属性、方法等。 2、开放封闭原则(OCP) 一个类应该对扩展开放,对修改关闭。这意味一旦创建了一个类并且应用程序的其他部分开始使用它,就不应该修改它。简单地说:就是当别人要修改软件功能的时候https://www.51cto.com/article/707554.html
8.www.solidjs.cn/guides/gettingSolid 拥有动态的服务器端渲染解决方案,可实现真正的同构开发体验。通过使用我们的 Resource primitive,很容易进行异步数据请求,更重要的是,我们也可以在客户端和浏览器之间自动序列化和同步。由于Solid 支持服务器上的异步和流式渲染,因此你可以以一种方式编写代码并让它在服务器上执行。这个特性类似 render-as-you-https://www.solidjs.cn/guides/getting-started
9.5月晨读前半部分汇总61. be booked solid solid 除了固体的,也可以表示纯的,比如solid gold。也可以表示实实在在的,充分的,比如这课学的 be booked solid。用来形容人还可以表示可靠的a solid citizen。 62. my hands are tied 我也无能为力 63. short-staffed 缺人手 short-handed https://www.jianshu.com/p/d7c6163ce767
10.固体核磁SolidNMR研究简介教学PPT课件SolidSolid--NMRNMR2固体固体NMRNMR研究的对象与特点研究的对象与特点固体高分辨固体高分辨NMRNMR在材料结构研究中的应用在材料结构研究中的应用核磁共振波谱在无机和金属化合物方面的应用核磁共振波谱在无机和金属化合物方面的应用生物大分子微观结构的研究生物大分子微观结构的研究I(I(自旋量子数自旋量子数))天然丰度天https://www.docin.com/p-2420911814.html
11.Atlas2/Wiki/AtlasFor SOLiD data SOLiD-SNP-caller \<in.bam> \<ref.fa> [.bed region] > [output.vcf] SOLiD-SNP-caller is coded in C++ and basic usage can be viewed by running the program without any argument. \<in.bam> FILE BAM format alignment file (Required to be sorted by start position) https://sourceforge.net/p/atlas2/wiki/Atlas-SNP/
12.AdminLTE2Documentation Box Tools Boxes can contain tools to deploy a specific event or provide simple info. The following examples makes use of multiple AdminLTE components within the header of the box. AdminLTE data-widget attribute provides boxes with the ability to collapse or https://adminlte.io/themes/AdminLTE/documentation/
13.SolidStateSociety———对于谜底和SAC的讨论(攻壳机动队SSS而两年前古式孝彰所做的事仅仅是构建Solid State Society,并将孤儿们送到老人身边,这时的SSS还没有绑架系统。在少佐后来多线操作利用这副义体行动的同时,一部分意识在少佐的不自觉下开始独自行动编织SSS中的绑架系统,傀儡廻就此诞生。而影片的最后,那部分意识并没有随着傀儡廻消失,而是逃走去“孕育下一个社会”。https://movie.douban.com/review/6700946/
14.structureViz:LinkingCytoscapeandChimerasurfacestyle=[none|solid|mesh|dot]: This is the style of depiction to use for surfaces in the specified structurelist or atomspec argument. Like ribbonstyle this argument causes the surface to be calculated and displayed. structurelist=structurelist: This is the list of structures (in the formhttp://www.cgl.ucsf.edu/cytoscape/structureViz
15.LetPubSOLIDSTATEIONICS影响因子3.000分,是几区,2023LetPub整理了最新的SOLID STATE IONICS 期刊投稿经验, 期刊官方投稿网址,影响因子,审稿周期/时间,研究方向,SCI期刊分区,中国作者发表的文章等信息, 以供中国作者投稿前参考。http://www.letpub.com.cn/index.php?page=journalapp&view=detail&journalid=7564
16.元动力——固态电池行业概论与投资思考Solid Power核心产品为软包全固态电池和硫化物固态电解质。2023年营收1741万美元,净利润-6554万美元;2022年营收1179万美元,净利润-956万美元。 电芯方案与指标: (第一代):硫化物电解质,正极NCM811/负极富硅负极,容量2-20Ah,能量密度390Wh/kg,循环寿命1000次。 https://36kr.com/p/2862982202399105
17.工程力学计算软件有哪些14. solid edge solid edge是一款3d cad软件,提供了广泛的机械、电气、建筑等行业的解决方案,其可扩展性和易用性也受到用户的广泛好评。该软件采用基于订阅的价格模式,用户只需要支付对应数量的年度订阅费用即可,价格相对合理。 15. catia catia是一款流行的cad工具和产品生命周期管理软件,除了支持各种cad标准之外,该https://h.chanjet.com/ask/fac8779533b09.html
18.加载电流激励时的stranded和solid选项有什么区别!?22:21 编辑 如题!我的理解solid应该是电流在面域均匀分布,但是straned就不知道了,请达人指点!https://bbs.simol.cn/thread-10219-1-1.html
19.solid在食品词典中的意思,短语,例句,发音,词形变化,以及相关专业solid 的解释:n. 固体;a. 坚硬的,稳固的; ;以及相关食品领域中相关专业词汇http://dict.foodmate.net/solid
20.css中的solid是什么意思css教程Solid 在 CSS 中表示实线边框,通过https://m.php.cn/faq/768762.html
21.solid的用法总结(精选13篇)【导语】下面是小编整理的solid的用法总结(共13篇),欢迎大家阅读分享借鉴,希望对大家有所帮助。篇1:solid的用法总结solid的意思adj.固体的,实心的,结实的,可靠的,可信赖的.固https://www.hrrsj.com/gongzuozongjie/qitazongjie/267426.html
22.Solid查看?Solid?的翻译、定义、含义、转录和例句,学习?Solid?的同义词、反义词和发音。https://cn.englishlib.org/dictionary/en-cn/solid.html
23.4.AdvancedFileI/OMany systems thus use the Noop I/O Scheduler for solid-state storage, as it provides merging (which is beneficial) but not sorting. Systems, however, that wish to optimize for interactive performance prefer the fairness of the CFQ I/O Scheduler, even for SSDs. Selecting and Configuring Yourhttps://www.oreilly.com/library/view/linux-system-programming/9781449341527/ch04.html
24.SimpleITMarkdown│ │ briefcase-solid.svg │ │ envelope-solid.svg │ │ evaluate-solid.svg │ │ github-brands.svg │ │ graduation-cap-solid.svg │ │ honor-solid.svg │ │ info-circle-solid.svg │ │ info-solid.svg │ │ phone-solid.svg https://gitee.com/lcry/Simple-IT-Markdown-Resume/
25.空手撸SOLID架构设计原则,六大原则层层解析,你绝想不到设计原则概述 通常来说,要想构建—个好的软件系统,应该从写整洁的代码开始做起。毕竟,如果建筑所使用的砖头质量不佳,那么架构所能起到的作用也会很有限。反之亦然,如果建筑的架构设计不佳,那么其所用的砖头质量再好也没有用。这就是SOLID设计原则所要解决的问题。 SOLhttps://maimai.cn/article/detail?fid=1808319238&efid=ELyy2cxgiMSx52gz8GgUEw
26.25款活泼大气的粉色系网页设计Bakerella Angie Dudley 的这个博客当中包含了大量的关于蛋糕和各种甜品的食谱与烹饪技巧,粉色无疑让人胃口大开。 Solidgiant SolidGiant 其实并非大型企业,但是粉色、红色与黑色的使用让整个网页布局显得大气磅礴。http://www.cndesign.com/news/3ba18d6f-3eb9-44a7-9182-a6f900d824c0.html
27.市面上的数控加工编程软件介绍Mastercam切割/雕刻SolidCAM 是一款集成于 SolidWorks 的数控编程软件,具有强大的 CAD/CAM 紧密集成功能。它能够生成高效、准确的刀具路径,并提供全面的仿真和验证,以确保加工过程的精确性和安全性。 7.SURFCAM: SURFCAM 是一款功能强大的数控编程软件,适用于铣削、车削、螺纹和线切割等加工操作。它具有直观易用的用户界面和先进的切削路https://www.ruanfujia.com/11163653/
28.qmail安装文档dupeng1445.2.3、Solid Solid POP3服务器支持maildir和mbox邮箱。主页在。 5.2.4、imap-maildir David R. Harris整理了华盛顿大学(University of Washington)IMAP服务器。文档和安装过程参见。 5.2.5、Courier-IMAP Sam Varshavchik编写了一个只支持maildir邮箱的IMAP服务器,见。 5.3、POP和IMAP客户端 5.3.http://blog.chinaunix.net/uid-643653-id-2082049.html
29.SCIENCEOFADVANCEDMATERIALSSolid-State Electrolyte for All Solid State Li-Ion Batteries Jie Chang, Yazhou Kong, Yunpeng Zhu, Yikai Gao, Canhuang Xie, Yu Chen, Wei Qian, Shihang Hu, Guang Hu, Jianxiong Wang, Huanjun Lu, Weiwei Hu, and Kailong Zhang Sci. Adv. Mater. 16, 783–788 (2024)[Abstract] [Full http://www.aspbs.com/sam.htm
30.PtypeβGa2O3metalsemiconductormetalsolarIn situ N-doping within the β-Ga2O3 films was controlled by decomposition rate of GaN, solid-solid phase-transition from GaN to β-Ga2O3, oxygen pressure, and Ar gas purge. Device fabrication The surface P-type electrical properties of the grown β-Ga2O3 films P-type doping is veryhttps://www.sciencedirect.com/science/article/abs/pii/S254252932030050X