In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-03-26 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/03 Report--
This article mainly introduces how to use dependency injection in Angular, has a certain reference value, interested friends can refer to, I hope you can learn a lot after reading this article, let the editor take you to understand it.
What is dependency injection
Control inversion (IoC)
The concept of control inversion was first put forward by Martin Fowler in 2004. It is a design principle aiming at the increasing complexity of object-oriented design. It is a design pattern that uses object-oriented programming rules to reduce application coupling.
IoC emphasizes that the control of code references is transferred from the caller to the external container, and is injected in some way when running, which greatly reduces the coupling between programs. Dependency injection is one of the most common ways to implement IoC, and the other is dependency lookup.
Dependency injection (Dependency Injection)
Of course, according to the usual practice, we should give an example, oh yes, what we are mainly talking about is dependency injection. Please check the data on your own.
Suppose we have a HRobot that can make hamburgers and need to use meat (meat) and some salads (salad) as raw materials, we can do this:
Export class HRobot {public meat: Meat; public salad: Salad; constructor () {this.meat = new Meat (); this.salad = new Salad ();} cook () {}}
There seems to be no problem. You may have found that our raw materials are all in the machine. If we want to eat other flavors of hamburgers, we may have to go to the village base.
In order to eat other flavors of hamburgers, we had to modify our HRobot:
Export class HRobot {public meat: Meat; public salad: Salad; constructor (public meat: Meat, public salad: Salad) {this.meat = meat; this.salad = salad;} cook () {}}
Now, just give it meat and salad directly, and our HRobot () doesn't need to know what kind of meat is given to it:
Let hRobot = new HRobot (new Meat (), new Salad ())
For example, if we want a chicken burger, all we need is a piece of chicken:
Class Chicken extends Meat {meat = 'chiken';} let cRobot = new HRobot (new Chicken (), new Salad ())
It feels good, and it's incredible that we won't bother to retrofit a machine to eat a chicken burger.
I may have thought that you are still too lazy to get a piece of chicken for it, so you can use the factory function:
Export class HRobotFactory {createHRobot () {let robot = new HRobot (this.createMeat (), this.createSalad ());} createMeat () {return new Meat ();} creatSalad () {return new Salad ();}}
Now that there is a factory, there will be a steady stream of hamburgers to eat. Are you happy and surprised?
Well, there is no laziest, only lazier, even the factory is lazy to manage, I have nothing to say, fortunately we have the dependency injection framework provided by Angular, which allows you to reach out and have a hamburger!
Second, Angular dependency injection
Before introducing Angular dependency injection, let's take a look at three concepts:
Injector (Injector): like a manufacturing factory, it provides a series of interfaces for creating instances of dependent objects.
Provider (Provider): used to configure the injector, which creates an instance of the dependent object, and Provider maps the Token to the factory method through which the dependent object is created.
Denpendence: the type of dependent object is specified, and the injector creates the corresponding object based on this type.
What is it like after talking for a long time?
An example of the code is as follows:
Var injector = new Injector (...); var robot = injector.get (HRobot); robot.cook ()
The implementation of Injector () is as follows:
Import {ReflecttiveInjector} form'@ angular/core';var injector = ReflectiveInjector.resolveAndCreat ([{provide: HRobot, useClass: HRobot}, {provide: Meat, useClass: Meat}, {provide: Salad, useClass: Salad}])
And the injector knows that initializing HRobot depends on Meat and Salad:
Export class Robot {/ /... Consructor (public meat: Meat, public salad: Salad) {} / /.}
Of course, it's okay to look big, because you don't have to write it yourself at all, and Angular's dependency injection framework has done it for us automatically (injector generation and invocation).
1. Inject services into a component
Angular does a lot of initialization work at the bottom, which greatly reduces the cost of using dependency injection. Now we only need three steps to complete dependency injection:
Import dependent object services through import
Configure the injector in the component. When starting the component, Angular reads the providers metadata in the @ Component decorator, which is an array that configures all the dependencies that the component needs to use. Angular's dependency injection framework creates a corresponding example based on this list.
Declare the dependency that needs to be injected in the component constructor. According to the declaration on the constructor, the injector configures the dependency through the providers metadata in the second step, provides the corresponding dependency service for the constructor, and finally completes the dependency injection.
Here's an example:
/ / app.component.ts//...// 1. Import the dependent object's service import {MyService} from'. / my-service/my-service.service';@Component ({/... / / 2. Configure the injector providers in the component: [MyService] / /.}) export class AppComponent {/ / 3. Declare the dependency constructor (private myService: MyService) {}} that needs to be injected in the constructor
two。 Inject a service into a service
In addition to component dependencies on services, mutual invocation between services is also common. For example, we want to add a counter to our hamburger robot to record its production, but the counter works on power, so we can do it with a service:
/ / power.service.tsimport {Injectable} from'@ angular/core';@Injectable () export class PowerService {/ / power come from here..} / / count.service.tsimport {Injectable} from'@ angular/core';import {PowerService} from'. / power/power.service' @ Injectable () export class CountService {constructor (private power: PoowerService) {}} / / app.component.ts here is the current component. In fact, the same is true for the injection in the module. We will talk about / /... providers: [CountService, PowerService]
It should be noted that the @ Injectable decorator is optional, because @ Injectable explicit decoration must be used only when a service depends on other services to indicate that the service needs to be dependent, so our PowerService does not have to add the @ Injectable decorator. However, Angular officially recommends that @ Injectable should be used to decorate the service.
3. Inject services into the module
Registering a service in a module is the same as registering a service in a component, except that the services injected into the module are available throughout the component.
/ / app.module.tsimport {BrowserModule} from'@ angular/platform-browser';import {NgModule} from'@ angular/core';import {AppComponent} from'. / app.component';@NgModule ({declarations: [AppComponent,], imports: [BrowserModule], providers: [CountService, PowerService], bootstrap: [AppComponent]}) export class AppModule {}
Unlike injecting into a component, when the Angular application starts, it loads all the dependencies needed by the module first, and a global root injector is generated, and the dependency injection objects created by this dependency are visible throughout the application and share an instance.
Angular does not have the concept of module-level scope, only application-level scope and component-level scope. This design mainly considers the expansibility of modules. An application is usually merged by multiple modules, and services registered in @ NgModule are available throughout the application by default.
Here are two special cases:
Suppose you inject the same service using the same Token in both modules, and the two modules are imported into the root component one after another:
/ /... @ NgModule ({imports: [AModule, BModule] / /...})
Then the services in the later imported module will overwrite the services in the previous imported module, that is, the services in BModule will overwrite the services in AModule, even if the services injected in AModule use the instances provided in BMoudle.
Again, assume that two modules inject the same service using the same Token, but the BModule module is imported into the AModule module:
/ / a.module.ts//... @ NgModule ({imports: [BModule]})
So in this case, both modules use the services injected into AModule. It can be inferred that the service injected into the root module has the highest priority and you can safely use it anywhere.
III. Provider
1. The understanding of Provider
It is necessary for Provider to propose a separate section. In the second section above, we simply use one of the provider to talk about Provider in detail.
In Angular, Provider describes how the injector (Injector) initializes the dependent service corresponding to the Token. Provider is a runtime dependency that injectors rely on to create instances of service objects.
For example, the example we used above:
/ /. @ Component ({/... / / 2. Configure the injector providers in the component: [MyService] / /.})
In fact, its complete form should look like this:
@ Component ({/... / / 2. Configure the injector providers in the component: [{provide: MyService, useClass: MyService}] / /...})
So we only use one kind of provider: class Provider (ClassProvider) above.
2. Provider registration method
As mentioned above, I have only used one of the registration methods, so here are four common registration methods provided in Angular:
Class Provider (ClassProvider)
Value Provider (ValueProvider)
Alias Provider (ExistingProvider)
Factory Provider (FactoryProvider)
1. Provider-like
The class Provider specifies dependencies based on Token, which allows dependencies to be dynamically specified as other concrete implementations that are transparent to the user as long as the interface remains the same. For example, data rendering service (Render). The interface provided by Render service to the upper layer is fixed, but the rendering method at the bottom layer can be different:
```tsvar inject = Injector.resolveAndCreate ([{provide: Render, useClass: DomRender} / / {provide: Render, useClass: DomRender} / / canvas rendering method / / {provide: Render, useClass: DomRender} / / the desired dyeing method of the service]) / / the caller does not need to make any changes to class AppComponent {construtor (private render: Render) {}} ``
two。 Value Provider
Because the dependent objects are not necessarily classes, they can also be strings, constants, objects and other data types, which can be easily used in global variables and system-related parameter configuration scenarios. When you create a Provider object, you only need to use useValue to declare a value Provider:
````tslet freeMan = {freeJob: boolen; live: () = > {return'do something u cant do'}}; @ Component ({/ /... Providers: [{provide: 'someone', useValue: freeMan}]}) ```
3. Alias Provider
With the alias Provider, we can configure multiple Token in a Provider, whose object points to the same instance, thus realizing the function of multiple dependencies and one object instance:
/ /... Providers: [{provider: Power1, useClass: PowerService}, {provider: Power2, useClass: PowerService}] / /...
Think about it. Is that right?
Obviously not, if both use useClass, then two different instances will be created according to tokens, so how should two tokens be implemented in the same instance? The answer is to use useExistiong:
/ /... Providers: [{provider: Power1, useClass: PowerService}, {provider: Power2, useExisting: PowerService}] / /...
4. Factory Provider
Factory Provider allows us to instantiate different services according to different conditions. For example, we need to print logs in the development environment, but we may not need to print these things in actual deployment, so it is impossible for us to find all the console.log () methods in the whole application. At this time, we can use factory provider to help us. We just need to set a condition in the factory provider. To enable it to return to instantiate the services we need according to the conditions. To achieve this function, we can inject this into the root module as follows:
````ts// app.module.ts@NgModule ({/ /... providers: [HeroService, ConsoleService, {provide: LoggerService, useFactory: (consoleService) = > {return new LoggerService (true, consoleService);}, deps: [ConsoleService]}], bootstrap: [AppComponent]}) export class AppModule {}
Oh, the two services are written like this:
/ / console.service.ts / /... Export class ConsoleService {log (message) {console.log (`ConsoleService: ${message} `);}} / / logger.service.ts / /. Export class LoggerService {constructor (private enable: boolean, consoleService: ConsoleService) {} log (message: string) {if (this.enable) {console.log (`LoggerService: ${message} `);}
Then write the required services in the component constructor.
Fourth, dependency injection in a limited way
Imagine a scenario where the provider of a service in your application is deleted as invalid code, and something may go wrong with your application. Fortunately, this problem was taken into account at design time, and we can use the @ Optional and @ Host decorators provided by Angular to solve this problem.
Optional can be compatible with situations where dependencies do not exist and improve the robustness of the system; @ Host can limit lookup rules, specify the location of instantiation, and avoid some inexplicable shared object problems.
@ Optional
Optional injection can be achieved with @ Optional:
/ / app.component.ts//... import {Optional} from'@ angular/core';constructor (@ Optional () private logger: LoggerService) {if (this.logger) {this.logger.log ('i am choosed');}}
As in the example, you only need to add the @ Optional decorator to the constructor of the host component (Host Component).
It is important to note that the LoggerService in the above example is not non-existent, but is not instantiated according to the configuration in the providers metadata.
@ Host
The rule of dependency lookup in Angular is to follow the injector from the current component to the parent component until the location of the dependency to be injected is found, and an error will be reported if it cannot be found. We can use the @ Host decorator provided by Angular to solve this problem.
Host component if a component injects dependencies, the component is the host component of the dependency; if the component is embedded in the parent component, then the parent component is the host component of the dependency.
1. The host component is the current component
We add the @ Host decorator to the component constructor:
/ /. @ Component ({selector: 'parent', template: `here is the parent component`}) constructor (@ Host () logger: LoggerService) {} / / add @ Host will report an error, because we have not injected LoggerService / / but we can add @ Optional to avoid reporting an error / / @ Host () / / @ Optional () / / logger: LoggerService) {}))
2. The host component is the parent component
Let's modify the above component to be the parent component:
/ / parent.component.ts /. @ Component ({selector: 'parent', template: `this is the parent component` / / inject LoggerService providers: [LoggerService]} into the parent component) constructor () {}
Add a subcomponent:
/ / child.component.ts /. @ Component ({selector: 'child', template: `here is the child component`}) constructor (@ Host () @ Optional () logger: LoggerService)) {}
Of course, this should be written in the label:
Because the host component is the parent component at this time, injecting the LoggerService Angular injector into the parent component automatically looks up to find the configuration in the ParentComponet to complete the injection.
Thank you for reading this article carefully. I hope the article "how to use dependency injection in Angular" shared by the editor will be helpful to everyone. At the same time, I also hope you will support us and pay attention to the industry information channel. More related knowledge is waiting for you to learn!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.