How to get once instance of service with Inject

孤人 提交于 2019-12-10 11:26:36

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!