我目前正在用nodejs创建一些实验性项目。我用Spring编写过很多Java EE web应用程序,非常欣赏依赖注入的便利性。
现在我很好奇:如何对节点进行依赖注入?或者:我真的需要它吗?因为编程风格不同,是否存在替代概念?
到目前为止,我谈论的是一些简单的事情,比如共享数据库连接对象,但我还没有找到一个让我满意的解决方案。
我目前正在用nodejs创建一些实验性项目。我用Spring编写过很多Java EE web应用程序,非常欣赏依赖注入的便利性。
现在我很好奇:如何对节点进行依赖注入?或者:我真的需要它吗?因为编程风格不同,是否存在替代概念?
到目前为止,我谈论的是一些简单的事情,比如共享数据库连接对象,但我还没有找到一个让我满意的解决方案。
当前回答
我最近检查了这个线程,原因和OP差不多——我遇到的大多数库都临时重写了require语句。我用这种方法取得了不同程度的成功,所以我最终使用了下面的方法。
在一个快速应用程序的上下文中-我将app.js包装在bootstrap.js文件中:
var path = require('path');
var myapp = require('./app.js');
var loader = require('./server/services/loader.js');
// give the loader the root directory
// and an object mapping module names
// to paths relative to that root
loader.init(path.normalize(__dirname), require('./server/config/loader.js'));
myapp.start();
传递给加载器的对象映射是这样的:
// live loader config
module.exports = {
'dataBaseService': '/lib/dataBaseService.js'
}
// test loader config
module.exports = {
'dataBaseService': '/mocks/dataBaseService.js'
'otherService' : {other: 'service'} // takes objects too...
};
然后,不要直接调用require…
var myDatabaseService = loader.load('dataBaseService');
如果加载器中没有别名,那么它将默认为常规require。 这样做有两个好处:我可以交换类的任何版本,并且消除了这种需要 在整个应用程序中使用相对路径名(因此如果我需要下面的自定义库 或以上的当前文件,我不需要遍历,并要求将缓存模块针对相同的关键)。它还允许我在应用程序的任何位置指定模拟,而不是在立即的测试套件中。
为了方便起见,我刚刚发布了一个小的npm模块:
https://npmjs.org/package/nodejs-simple-loader
其他回答
为了很好地测试应用程序,大多数时候最好使用反转控制工具在运行/测试时注入所需的对象。 所以最好不要在模块中直接使用require或import。而是调用DI容器来获取所需的对象。
如果你不想使用第三方库,你可以通过创建一个定制的DI容器来模仿IoC工具的行为。 在测试的时候,你可以模拟你的DI容器,并注入你的假模块用于测试。 下面是一个自定义DI容器的例子,这个版本的容器不支持接口。
myDependecy.js
const myDependecy = {};
export default myDependecy;
myDependecy.myTestFunction = () => {
console.log("this is as test function.");
};
diContainer.js
import myDependecy from "./myDependecy.js";
const diContainer = {};
export default diContainer;
diContainer.myDependecy = myDependecy;
myModule.js
import diContainer from "./diContainer.js";
function myFunction() {
diContainer.myDependecy.myTestFunction();
}
Node.js和其他平台一样需要DI。如果您正在构建一些大的东西,DI将使您更容易模拟代码的依赖关系并彻底测试代码。
例如,数据库层模块不应该只在业务代码模块中使用,因为在单元测试这些业务代码模块时,dao将加载并连接到数据库。
一种解决方案是将依赖项作为模块参数传递:
module.exports = function (dep1, dep2) {
// private methods
return {
// public methods
test: function(){...}
}
}
通过这种方式,依赖关系可以轻松自然地模拟,你可以专注于测试你的代码,而不需要使用任何棘手的第三方库。
还有其他的解决方案(百老汇,建筑师等)可以帮助你解决这个问题。尽管他们可能做的比你想要的多,或者使用更多的杂物。
我一直很喜欢IoC的简单理念——“你不需要了解任何环境,需要的时候有人会叫你。”
但是我看到的所有IoC实现都完全相反——它们用更多的东西使代码变得混乱。所以,我创建了我自己的IoC,就像我想要的那样-它保持隐藏和不可见的90%的时间。
它用于MonoJS web框架http://monojs.org
我说的是简单的事情,比如共享一个数据库连接对象 但我还没有找到一个让我满意的解决办法。
它是这样做的——在配置中注册组件一次。
app.register 'db', ->
require('mongodb').connect config.dbPath
可以在任何地方使用
app.db.findSomething()
你可以在https://github.com/sinizinairina/mono/blob/master/mono.coffee这里看到完整的组件定义代码(包括DB Connection和其他组件)
这是你必须告诉IoC该做什么的唯一地方,之后所有这些组件都将自动创建和连接,你不再需要在应用程序中看到IoC特定的代码。
国际奥委会本身https://github.com/alexeypetrushin/miconjs
它应该像这样灵活和简单:
var MyClass1 = function () {}
var MyClass2 = function (myService1) {
// myService1.should.be.instanceof(MyClass1);
}
container.register('myService1', MyClass1);
container.register('myService2', MyClass2, ['myService1']);
我写过一篇关于node.js中的依赖注入的文章。
管理你的服务-node.js依赖注入 包文档在这里
我希望它能帮到你。
我认为其他的文章在使用DI的论证方面做得很好。对我来说,原因是
注入依赖项而不知道它们的路径。这意味着如果您更改磁盘上的模块位置或将其与另一个模块交换,则不需要触及依赖于该模块的每个文件。 它使模拟依赖关系以进行测试变得更加容易,而不用痛苦地重写全局require函数,而且不会出现任何问题。 它可以帮助您将应用程序组织为松散耦合的模块。
但是我很难找到一个我和我的团队可以轻松采用的依赖注入框架。所以我最近基于这些特性构建了一个名为deppie的框架
可以在几分钟内学会的最小API 不需要额外的代码/配置/注释 一对一直接映射需要的模块 可以部分地使用现有代码吗