问题
I am trying to achieve dependency injection on my node project via inversify.
I have a kernel config like this: inversify.config.ts
import "reflect-metadata";
import {Kernel, interfaces} from "inversify";
import {Config} from "./config";
import {Collection} from "./collection";
let kernel = new Kernel();
kernel.bind<Config>("Config").to(Config).inSingletonScope();
// kernel.bind<interfaces.Newable<Collection>>("Collection").toConstructor<Collection>(Collection);
// it works without the line above
A class: config.ts
import {injectable} from "inversify";
@injectable()
export class Config {
constructor() {}
}
A class with property DI collection.ts
import {injectable} from "inversify";
import getDecorators from "inversify-inject-decorators";
import kernel from "../inversify.config";
let {lazyInject} = getDecorators(kernel);
@injectable()
export class Collection {
@lazyInject(Config)
private Config: Config;
constructor(a: string, b: string) {}
}
Everything works as expected if I don't bind a class with property injection. When I try to bind a class with @lazyInject
as shown in the example
kernel.bind<interfaces.Newable<Collection>>("Collection").toConstructor<Collection>(Collection);
import line in inversify.config.ts
starts processing Collection.ts
and the line
import kernel from "../inversify.config";`
in it. However as we arrived Collection.ts
while we already processing inversify.config.ts
file line
import kernel from "../inversify.config";`
somehow returns undefined
making kernel undefined
for Collection
class. Therefore @lazyInject
DI fails.
Eventually when I try to read Config
in Collection
it fails with:
TypeError: Cannot read property 'get' of undefined
at resolve (node_modules/inversify-inject-decorators/lib/decorators.js:24:30)
at Category.getter (node_modules/inversify-inject-decorators/lib/decorators.js:6:47)
I wonder if there is a way to accomplish binding a class with property DI via @lazyInject
without moving kernel definition into the same file with one of the classes. I am looking for a way to import kernel as it is now, but make it work properly.
回答1:
Your problem is that you have a circular dependency:
I'm going to change your code and add a couple of additional files. Nothe that the he file types.ts
is not needed but it is recommended to keep all your type identifiers in one single location.
After changing your code the dependency diagram will change to the following:
As you can se we have eliminated the circular dependency.
inversify.config.ts
import "reflect-metadata";
import {Kernel, interfaces} from "inversify";
import getDecorators from "inversify-inject-decorators";
import { makeProvideDecorator } from "inversify-binding-decorators";
let kernel = new Kernel();
let {lazyInject} = getDecorators(kernel);
let provide = makeProvideDecorator(kernel);
export { lazyInject, provide };
types.ts
let TYPES = {
Config: "Config",
Collection: "Collection",
};
export default TYPES;
config.ts
import { provide } from "../inversify.config";
import TYPES from "./types";
@provide(TYPES.Config)
export class Config {
constructor() {}
}
export default Config;
collection.ts
import { lazyInject, provide } from "../inversify.config";
@provide(TYPES.Collection)
export class Collection {
@lazyInject(TYPES.Config)
private Config: Config;
constructor(a: string, b: string) {}
}
export default Collection;
main.ts
You need to import all your dependencies when they are imported @provide is executed and then bindings are generated.
import Config from "./lib/config";
import Collection from "./models/collection";
//...
We have been able to eliminate the circular dependency using the @provide
decorator from inversify-binding-decorators.
来源:https://stackoverflow.com/questions/38927236/binding-classes-with-property-injection-to-kernel-in-inversify