容器接口
InversifyJS 容器提供一些配置和方法,帮助解决多个注入和模糊绑定。
容器选项
defaultScope
默认生命周期是 transient
,可以在声明绑定时更改生命周期管理类型:
container.bind<Warrior>(TYPES.Warrior).to(Ninja).inSingletonScope();
container.bind<Warrior>(TYPES.Warrior).to(Ninja).inTransientScope();
您可以配置容器选项,来更改默认生命周期为应用程序级别:
let container = new Container({ defaultScope: "Singleton" });
autoBindInjectable
您可以使用它为 @injectable()
装饰过的类激活自动绑定:
let container = new Container({ autoBindInjectable: true });
container.isBound(Ninja); // returns false
container.get(Ninja); // returns a Ninja
container.isBound(Ninja); // returns true
手动定义的绑定优先级更高:
let container = new Container({ autoBindInjectable: true });
container.bind(Ninja).to(Samurai);
container.get(Ninja); // returns a Samurai
Container.merge(a: Container, b: Container)
将两个容器合并为一个容器:
@injectable()
class Ninja {
public name = "Ninja";
}
@injectable()
class Shuriken {
public name = "Shuriken";
}
let CHINA_EXPANSION_TYPES = {
Ninja: "Ninja",
Shuriken: "Shuriken"
};
let chinaExpansionContainer = new Container();
chinaExpansionContainer.bind<Ninja>(CHINA_EXPANSION_TYPES.Ninja).to(Ninja);
chinaExpansionContainer.bind<Shuriken>(CHINA_EXPANSION_TYPES.Shuriken).to(Shuriken);
@injectable()
class Samurai {
public name = "Samurai";
}
@injectable()
class Katana {
public name = "Katana";
}
let JAPAN_EXPANSION_TYPES = {
Katana: "Katana",
Samurai: "Samurai"
};
let japanExpansionContainer = new Container();
japanExpansionContainer.bind<Samurai>(JAPAN_EXPANSION_TYPES.Samurai).to(Samurai);
japanExpansionContainer.bind<Katana>(JAPAN_EXPANSION_TYPES.Katana).to(Katana);
let gameContainer = Container.merge(chinaExpansionContainer, japanExpansionContainer);
expect(gameContainer.get<Ninja>(CHINA_EXPANSION_TYPES.Ninja).name).to.eql("Ninja");
expect(gameContainer.get<Shuriken>(CHINA_EXPANSION_TYPES.Shuriken).name).to.eql("Shuriken");
expect(gameContainer.get<Samurai>(JAPAN_EXPANSION_TYPES.Samurai).name).to.eql("Samurai");
expect(gameContainer.get<Katana>(JAPAN_EXPANSION_TYPES.Katana).name).to.eql("Katana");
container.getNamed()
绑定命名:
let container = new Container();
container.bind<Weapon>("Weapon").to(Katana).whenTargetNamed("japonese");
container.bind<Weapon>("Weapon").to(Shuriken).whenTargetNamed("chinese");
let katana = container.getNamed<Weapon>("Weapon", "japonese");
let shuriken = container.getNamed<Weapon>("Weapon", "chinese");
container.getTagged()
绑定标签:
let container = new Container();
container.bind<Weapon>("Weapon").to(Katana).whenTargetTagged("faction", "samurai");
container.bind<Weapon>("Weapon").to(Shuriken).whenTargetTagged("faction", "ninja");
let katana = container.getTagged<Weapon>("Weapon", "faction", "samurai");
let shuriken = container.getTagged<Weapon>("Weapon", "faction", "ninja");
container.getAll()
获取给定标识符的所有可用绑定:
let container = new Container();
container.bind<Weapon>("Weapon").to(Katana);
container.bind<Weapon>("Weapon").to(Shuriken);
let weapons = container.getAll<Weapon>("Weapon"); // returns Weapon[]
container.getAllNamed()
获取与给定命名约束匹配的,给定标识符的所有可用绑定:
let container = new Container();
interface Intl {
hello?: string;
goodbye?: string;
}
container.bind<Intl>("Intl").toConstantValue({ hello: "bonjour" }).whenTargetNamed("fr");
container.bind<Intl>("Intl").toConstantValue({ goodbye: "au revoir" }).whenTargetNamed("fr");
container.bind<Intl>("Intl").toConstantValue({ hello: "hola" }).whenTargetNamed("es");
container.bind<Intl>("Intl").toConstantValue({ goodbye: "adios" }).whenTargetNamed("es");
let fr = container.getAllNamed<Intl>("Intl", "fr");
expect(fr.length).to.eql(2);
expect(fr[0].hello).to.eql("bonjour");
expect(fr[1].goodbye).to.eql("au revoir");
let es = container.getAllNamed<Intl>("Intl", "es");
expect(es.length).to.eql(2);
expect(es[0].hello).to.eql("hola");
expect(es[1].goodbye).to.eql("adios");
container.getAllTagged()
获取与给定标签约束匹配的,给定标识符的所有可用绑定:
let container = new Container();
interface Intl {
hello?: string;
goodbye?: string;
}
container.bind<Intl>("Intl").toConstantValue({ hello: "bonjour" }).whenTargetTagged("lang", "fr");
container.bind<Intl>("Intl").toConstantValue({ goodbye: "au revoir" }).whenTargetTagged("lang", "fr");
container.bind<Intl>("Intl").toConstantValue({ hello: "hola" }).whenTargetTagged("lang", "es");
container.bind<Intl>("Intl").toConstantValue({ goodbye: "adios" }).whenTargetTagged("lang", "es");
let fr = container.getAllTagged<Intl>("Intl", "lang", "fr");
expect(fr.length).to.eql(2);
expect(fr[0].hello).to.eql("bonjour");
expect(fr[1].goodbye).to.eql("au revoir");
let es = container.getAllTagged<Intl>("Intl", "lang", "es");
expect(es.length).to.eql(2);
expect(es[0].hello).to.eql("hola");
expect(es[1].goodbye).to.eql("adios");
container.isBound(serviceIdentifier: ServiceIdentifier)
您可以使用 isBound
方法来检查,给定的服务标识符是否有注册过的绑定。
interface Warrior {}
let warriorId = "Warrior";
let warriorSymbol = Symbol.for("Warrior");
@injectable()
class Ninja implements Warrior {}
interface Katana {}
let katanaId = "Katana";
let katanaSymbol = Symbol.for("Katana");
@injectable()
class Katana implements Katana {}
let container = new Container();
container.bind<Warrior>(Ninja).to(Ninja);
container.bind<Warrior>(warriorId).to(Ninja);
container.bind<Warrior>(warriorSymbol).to(Ninja);
container.isBound(Ninja)).eql(true);
container.isBound(warriorId)).eql(true);
container.isBound(warriorSymbol)).eql(true);
container.isBound(Katana)).eql(false);
container.isBound(katanaId)).eql(false);
container.isBound(katanaSymbol)).eql(false);
container.isBoundNamed(serviceIdentifier: ServiceIdentifier, named: string)
您可以使用 isBoundNamed
方法来检查, 在给定命名约束下, 给定的服务标识符是否有注册过的绑定。
const zero = "Zero";
const invalidDivisor = "InvalidDivisor";
const validDivisor = "ValidDivisor";
let container = new Container();
expect(container.isBound(zero)).to.eql(false);
container.bind<number>(zero).toConstantValue(0);
expect(container.isBound(zero)).to.eql(true);
container.unbindAll();
expect(container.isBound(zero)).to.eql(false);
container.bind<number>(zero).toConstantValue(0).whenTargetNamed(invalidDivisor);
expect(container.isBoundNamed(zero, invalidDivisor)).to.eql(true);
expect(container.isBoundNamed(zero, validDivisor)).to.eql(false);
container.bind<number>(zero).toConstantValue(1).whenTargetNamed(validDivisor);
expect(container.isBoundNamed(zero, invalidDivisor)).to.eql(true);
expect(container.isBoundNamed(zero, validDivisor)).to.eql(true);
container.isBoundTagged(serviceIdentifier: ServiceIdentifier, key: string, value: any)
您可以使用 isBoundTagged
方法来检查, 在给定标签约束下, 给定的服务标识符是否有注册过的绑定。
const zero = "Zero";
const isValidDivisor = "IsValidDivisor";
let container = new Container();
expect(container.isBound(zero)).to.eql(false);
container.bind<number>(zero).toConstantValue(0);
expect(container.isBound(zero)).to.eql(true);
container.unbindAll();
expect(container.isBound(zero)).to.eql(false);
container.bind<number>(zero).toConstantValue(0).whenTargetTagged(isValidDivisor, false);
expect(container.isBoundTagged(zero, isValidDivisor, false)).to.eql(true);
expect(container.isBoundTagged(zero, isValidDivisor, true)).to.eql(false);
container.bind<number>(zero).toConstantValue(1).whenTargetTagged(isValidDivisor, true);
expect(container.isBoundTagged(zero, isValidDivisor, false)).to.eql(true);
expect(container.isBoundTagged(zero, isValidDivisor, true)).to.eql(true);
container.rebind(serviceIdentifier: ServiceIdentifier)
您可以使用 rebind
方法,来替代给定 serviceIdentifier
的所有已存在绑定。
这个方法返回的是一个 BindingToSyntax
实例,它能够替代绑定。
let TYPES = {
someType: "someType"
};
let container = new Container();
container.bind<number>(TYPES.someType).toConstantValue(1);
container.bind<number>(TYPES.someType).toConstantValue(2);
let values1 = container.getAll(TYPES.someType);
expect(values1[0]).to.eq(1);
expect(values1[1]).to.eq(2);
container.rebind<number>(TYPES.someType).toConstantValue(3);
let values2 = container.getAll(TYPES.someType);
expect(values2[0]).to.eq(3);
expect(values2[1]).to.eq(undefined);
container.resolve(constructor: Newable)
它的解析类似于 container.get<T>(serviceIdentifier: ServiceIdentifier<T>)
,但它允许用户创建实例,即使之前没有声明过绑定。
@injectable()
class Katana {
public hit() {
return "cut!";
}
}
@injectable()
class Ninja implements Ninja {
public katana: Katana;
public constructor(katana: Katana) {
this.katana = katana;
}
public fight() { return this.katana.hit(); }
}
const container = new Container();
container.bind(Katana).toSelf();
const tryGet = () => container.get(Ninja);
expect(tryGet).to.throw("No matching bindings found for serviceIdentifier: Ninja");
const ninja = container.resolve(Ninja);
expect(ninja.fight()).to.eql("cut!");
请注意,它只允许在依赖关系图的根元素(组合根)中跳过声明一个绑定。所有的子依赖(例如前面例子中的 Katana
)则需要声明对应的绑定。