当前位置:网站首页>Deep understanding of control inversion and dependency injection

Deep understanding of control inversion and dependency injection

2022-04-23 17:06:00 begeneral

I didn't quite understand these two concepts before , This period of time is learning ASP.NET CORE, and ASP.NET CORE It is based on the dependency injection framework , So I studied hard .

So called inversion of control , In fact, it is from active to passive . In the past, we had to new An object is very directly new, This is actually a violation of one of the most important principles of programming : Low coupling .

Because in A Class directly B Class causes A Is directly dependent on B Of , The scalability of the program designed in this way is very poor , This way we call it active .

What is passivity ? Passivity is A Class if you need to reference B class , Not in A Class B class , But provided by the framework B Class .

In this case , commonly B Class is inherited from an interface or abstract class ,A Class refers to an interface or abstract class , In this way, it conforms to the design principle of interface oriented programming ,A and B decoupling .

So when it comes to this , I'm sure you'll ask , How does the framework provide B Class instance ?

There are many ways , such as : Template method 、 Factory method 、 Abstract factory . The ideas of these methods are actually similar : Define an interface or abstract class C, Give Way B Inherit C, stay B To realize

Those abstract methods or virtual methods , I won't introduce this in detail .

Dependency injection is actually a framework for control inversion , Inversion of control is a design concept , Dependency injection is a framework to realize this idea , That's why their brothers are often

The reason for bringing it up together .

The popular explanation for dependency injection is : If A rely on B,B Inherit from interface or abstract class C, that A The reference in the class should be C, send A And B decoupling . How do you explain that ? In fact, when writing code

To configure C Implementation class of , After the program starts , The dependency injection framework will C and B The relationship is stored in a ServiceDescriptor Class , When A Need to use C when , The dependency injection framework will be based on B and C Instantiate a mapping relationship B Give to the A.

So it looks like , The name of dependency injection is quite appropriate, isn't it .

How does the dependency injection framework provide B Class instance ? Let's explain the internal implementation of the dependency injection framework from a purely theoretical point of view ( It's better to download ASP.NET CORE The source code of , In this way, you will understand in more detail )

The ways of dependency injection are 3 in : Constructor Injection 、 Attribute injection 、 Methods to inject . What we use most is constructor injection , Of course. ASP.NET CORE Of startup Class ConfigureServices and Configure Method injection is also used in the function .

Let's talk about the registration process of dependency injection first . Everyone knows that we call IServiceCollection Of Add Method to register the service (IServiceCollection There are several extension methods , You can add services with different life cycles , But it's all calls in the end Add Method ),

How does this framework store these registration information ? If you don't consider the details , In fact, it's quite simple . Is in the ServiceCollection(IServiceCollection The default implementation of the interface ) It defines List<ServiceDescriptor> Global variable of type ,

All parameters of a registered service are defined in ServiceDescriptor Class , such as : Service type (ServiceType)、 Implementation types (ImplementationType)、 Life cycle (Lifetime) Equal attribute . Every time you add a service registration , This List Just add a ServiceDescriptor.

Registration is over , Let's talk about the consumption of services , This is how the framework instantiates the corresponding instance .

Let's first talk about some conditions that the registered implementation class needs to meet . First, the implementation class must have a public constructor , Otherwise, how to instantiate ? Second, if the constructor has parameters , That parameter must be

The dependency injection framework must be able to provide , For example, this parameter is an interface or abstract class that has been registered to the framework .

This leads to 2 A question , Let's take a look at the code :

services.AddSingleton<IFoo, Foo>();
services.AddSingleton<IBar, Bar>();
services.AddSingleton<IQux, Qux>();
public class Qux:IQux
    {
        public Qux(IFoo foo)
        {
            Console.WriteLine($"Selected constructor:Qux(IFoo foo)");
        }
        public Qux(IFoo foo,IBar bar)
        {
            Console.WriteLine($"Selected constructor:Qux(IFoo foo,IBar bar)");
        }
    }

Qux Yes 2 Constructors , Which one will the dependency injection framework choose ? We are in the IQux Put it in the constructor of a controller , Run up and have a look :

The selected constructor is the second , This example shows that the parameters of the constructor must be a subset of all the parameters that the dependency injection framework can provide . If no matching parameter is found, an error will be reported .

Let's look at another situation :

public class Qux:IQux
    {
        public Qux(IFoo foo,IBar bar)
        {
            Console.WriteLine($"Selected constructor:Qux(IFoo foo,IBar bar)");
        }
        public Qux(IFoo foo,IBaz baz)
        {
            Console.WriteLine($"Selected constructor:Qux(IFoo foo,IBaz baz)");
        }
    }
services.AddSingleton<IFoo, Foo>();
services.AddSingleton<IBar, Bar>();
services.AddSingleton<IBaz, Baz>();
services.AddSingleton<IQux, Qux>();

In this case, this 2 Both constructors satisfy , The framework cannot choose the appropriate constructor , It's a direct error .

Combined with the life cycle , Let's think a little more , If Qux The life cycle of is Singleton,Foo The life cycle of is Scope, and Qux Refer to the Foo, What will happen then ?

services.AddScoped<IFoo, Foo>();          
services.AddSingleton<IQux, Qux>();
public class Qux:IQux
    {
        public Qux(IFoo foo)
        {
            Console.WriteLine($"Selected constructor:Qux(IFoo foo)");
        }
 
    }

The running result is :

System.AggregateException:“Error while validating the service descriptor 'ServiceType: ValidateScope.IQux Lifetime: Singleton ImplementationType: ValidateScope.Qux': Cannot consume scoped service 'Vali”

It means that the life cycle is Singleton The type of Qux Cannot consume. The life cycle is Scope Of Foo. This is actually very easy to understand ,Singleton Services are stored in the root container , Is a singleton , Its life cycle is from the start of the program to the end of the program , Throughout the entire application lifecycle .

and Scope Services are sub containers stored under the root container , Its life cycle is from the beginning to the end of a request , If Singleton The service refers to Scope service , It's equivalent to putting Scope Service is put in Singleton Service went inside , But when you register, you register as Scope service , So this must be

Conflicting .

Let's talk about the creation process of service instance , Altogether 4 Create an instance of the service in the way :

1、RuntimeServiceProviderEngine, Provide service instances in a reflective way

2、ILEmitServiceProviderEngine, use IL Emit To provide service instances

3、ExpressionsServiceProviderEngine, Use expression tree to provide service instance

4、DynamicServiceProviderEngine, According to the number of concurrent requests, the final service instance provision scheme is determined dynamically

By default, the framework adopts the fourth method . In fact, I only know the way of reflection , Others don't know much , If you are interested, you can download it yourself ASP.NET CORE Study the source code of .

The above is my understanding of control inversion and dependency injection , If something is wrong , Please leave a message to correct , thank you !

 

 

 

 

 

 

版权声明
本文为[begeneral]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/04/202204230554081905.html