问题
How can I get the same once instance of singleton service using Injector:
I define provider of this service on the bootstrap application(for one instance on the all application)
Example:
Bootstrap application
//Init application
bootstrap(AppComponent, [ROUTER_PROVIDERS, HTTP_PROVIDERS, SessionService]);
SessionService
Singleton - this is just example, but in real can be session or acl service
@Injectable()
export class SessionService {
constructor() {
console.warn("INSTANCE OF SESSION SERVICE-a");
}
public getInstance(instanceName: string){
console.warn("Injected service come from component name: " + instanceName);
}
}
SecuredHomeComponent
When I inject service on the constructor has only once instance of services (good)
@Component()
@CanActivate(AccessService.checkSession)
export class SecuredHomeComponent {
public constructor(private testSessionService: SessionService) {
this.testSessionService.getInstance('Component1:1'); //Test 1 - get the same instance when service is inject into contructor
}
}
MyStaticService
I try like this, inject service but All the time get new Instance of service But I need inject directly into for example static method using "Injector.resolveAndCreate" then NG2 create new Instance of service (bad)
@Injectable()
export class MyStaticService {
public static getDataFromService() {
//That two ways is bad, bcs create new instance of my test SessionService
//Test4
let providers = Injector.resolve([ SessionService ]);
let injectorFirst = Injector.fromResolvedProviders(providers);
let testServFirst = injectorFirst.get(SessionService);
testServFirst.getInstance('StaticService1:1');
//Test 5
let injectorSecond = Injector.resolveAndCreate([SessionService]);
let testServSecond = injectorSecond.get(SessionService);
testServSecond.getInstance('StaticService1:2');
}
}
Static Service
For real example, I need static class with static method If I good understand doc, when want overwrites methods for annotation canActivate must provide servise with static method
Line: @CanActivate(AccessService.checkSession) in my "SecuredHomeComponent"
//Static Service - ACCESS
@Injectable()
export class AccessService {
public static checkAccess = (next: ComponentInstruction, prev: ComponentInstruction): boolean => {
return AccessService.checkSession() && AccessService.checkAcl(res, priv);
}
public static checkSession(): boolean {
let injectedSessionServices: SessionService; //How to inject the same instance of my SessionService?
return injectedSessionServices.getDataFromService(); //for real service he get back checkSession from sessionService
}
public static checkAcl(aclResource: AclResources, aclPrivilege: AclPrivileges): boolean {
let injectedAclServices: SessionService; //How to inject the same instance of my SessionService?
return injectedAclServices.checkAcl(aclResource, aclPrivilege);
}
}
回答1:
Angulars DI keeps one instance per provider. If an instance is requested from the same provider, the same instance is returned every time.
What you can do is, to provide a factory and call the factory to get a new instance.
bootstrap(AppComponent, [provide(CommonTestService, {useFactory: () => {
return () => {
new CommonTestService();
}
})]);
if the service itself has dependencies (constructor parameters) then you need to provide them as well
bootstrap(AppComponent, [MyServiceDependency, provide(CommonTestService, {useFactory: () => {
return () => {
new CommonTestService(dep);
},
deps: [MyServiceDependency]
})]);
Then you can use it like
@Component()
export class HomeComponent {
public constructor(@Inject(CommonTestService) private testService:any) {
let s1 = testService(); // new instance
let s2 = testService(); // new instance
..
}
}
回答2:
I find solution with using one instance of global service injector implemented standard singleton class with getInstance() into bootstrap application. And after that can get simple instance of injected service on all level of application. If some time somebody find different solution, or NG2 resolve this different pls let me know.
Sample code for very simple example:
Bootstrap app
//Init application
bootstrap(AppComponent, [ROUTER_PROVIDERS, MY_PROVIDERS, HTTP_PROVIDERS])
.then((appRef) => MainInjectorService.getInstance().setInjector(appRef.injector));
My helpers main injector
import { Injector, Injectable } from 'angular2/src/core/di';
@Injectable()
export class MainInjectorService
{
static instance:MainInjectorService;
static isCreating:Boolean = false;
private _injector: Injector;
constructor() {
if (!MainInjectorService.isCreating) {
throw new Error("You can't call new in Singleton instances!");
}
}
public static getInstance() {
if (MainInjectorService.instance == null) {
MainInjectorService.isCreating = true;
MainInjectorService.instance = new MainInjectorService();
MainInjectorService.isCreating = false;
}
return MainInjectorService.instance;
}
public setInjector(injector: Injector) {
this._injector = injector;
}
public getInjector(): Injector {
return this._injector;
}
}
My STATIC class
// Access - static service
@Injectable()
export class StaticAccessService {
// Get service instance from global provides service
private static _getService<T>(serviceName: any) {
let injector: Injector = MainInjectorService.getInstance().getInjector();
return injector.get(serviceName);
}
//Check access to session and acl
public static checkAccess = (next: ComponentInstruction, prev: ComponentInstruction): boolean => {
return StaticAccessService.checkSession() && StaticAccessService.checkAcl(next.routeData.data['res'], next.routeData.data['priv']);
}
// Check session access
public static checkSession(): boolean {
return StaticAccessService._getService(MySessionService).checkSession();
}
// Check session access
public static checkAccess(res, priv): boolean {
return StaticAccessService._getService(MyAclService).checkAccess(res, priv);
}
}
And how to use in component
@Component()
@CanActivate(StaticAccessService.checkAccess)
export class SecuredComponent {
}
来源:https://stackoverflow.com/questions/36222799/how-to-get-once-instance-of-service-with-inject