Interpretation of the Laravel service provider (serviceprovider)

Source: Internet
Author: User
This article mainly introduces the Laravel service provider (serviceprovider) interpretation, has a certain reference value, now share to everyone, the need for friends can refer to

The service provider is the boot Center for all Laravel applications. Your application-customized services, services provided by third-party resource bundles, and all core services of Laravel are registered (register) and boot (boot) through the service provider.

Take an example of a service provider that comes with a laravel framework

class Broadcastserviceprovider extends serviceprovider{protected $defer = True    ; Public Function Register () {$this->app->singleton (broadcastmanager::class, function ($app) {R        Eturn new Broadcastmanager ($app);        }); $this->app->singleton (Broadcastercontract::class, function ($app) {return $app->make (broadcastmanager        :: Class)->connection ();        }); Set Broadcastingfactory::class to alias of Broadcastmanager::class $this->app->alias (broadcastmanager::cl    , Broadcastingfactory::class); } public Function provides () {return [Broadcastmanager::class, BROADCASTINGFACTORY::C    Lass, Broadcastercontract::class,]; }}

In the service provider BroadcastServiceProvider , the class register name is bound to the BroadcastingFactory class implementation Broadcastmanager, which enables the service container to make out the BroadcastingFactory::class bound service BroadcastManger object for use by the application.

The main time of this article is to comb how laravel is registering, and initializing these services, and about how to write your own service provider, which can refer to the official documentation

BootStrap

First of all, the services required to register and boot the application are laravel in the bootstrap phase of the search for a routing client request, and in the framework's entry file we can see that the framework Application resolves the object from the service container after instantiating the object HTTP Kernel

$kernel = $app->make (illuminate\contracts\http\kernel::class), $response = $kernel->handle (    $request = Illuminate\http\request::capture ());

When kernel processes a request, the request passes through the middleware and then sends the request to the Controller method that corresponds to the route, before which there is a bootstrap stage to boot the Laravel application, as shown in the following code.

public function handle ($request) {... $response = $this->sendrequestthro    Ughrouter ($request); ... return $response;} 
protected function Sendrequestthroughrouter ($request) {$this->app->instance (' request ', $request);    Facade::clearresolvedinstance (' request ');    $this->bootstrap (); Return (new Pipeline ($this->app))->send ($request)->through ($this->app- >shouldskipmiddleware ()?    []: $this->middleware)->then ($this->dispatchtorouter ());} Boot boot laravel application public Function bootstrap () {if (! $this->app->hasbeenbootstrapped ()) {/** Execute $bootstrap sequentially The Bootstrap () function of each bootstrapper in pers = [' Illuminate\foundation\bootstrap\detectenvironme NT ', ' illuminate\foundation\bootstrap\loadconfiguration ', ' Illuminate\foundation\bootstrap\configu Relogging ', ' illuminate\foundation\bootstrap\handleexceptions ', ' illuminate\foundation\bootstrap\r        Egisterfacades ', ' illuminate\foundation\bootstrap\registerproviders ',     ' Illuminate\foundation\bootstrap\bootproviders ',];*/$this->app->bootstrapwith ($this-&gt        ; Bootstrappers ()); }    }

Each bootstrapper bootstrap method is executed separately in the above bootstrap to boot the parts of the application

    1. detectenvironment  Check Environment    2. Loadconfiguration  Load application configuration    3. Configurelogging   Configuration Date to    4. HandleException    Registration exception handling for handler    5. Registerfacades    registered facades     6. Registerproviders  registered providers     7. Bootproviders      Start providers

The last two of the startup application is the registration service offering this and the start-up provider, which can be consulted if the previous stages are specific to the implementation of this article. Here we focus primarily on the registration and startup of service providers.

First look at registering a service provider, where the registration of a service provider is the responsibility of the class \Illuminate\Foundation\Bootstrap\RegisterProviders::class , which loads the register functions of all service providers and holds information for deferred services for lazy loading.

Class registerproviders{public    function bootstrap (application $app)    {        // Called application's registerconfiguredproviders ()        $app->registerconfiguredproviders ();}    }    Class Application extends Container implements Applicationcontract, httpkernelinterface{public    function Registerconfiguredproviders ()    {        (new Providerrepository ($this, new Filesystem, $this Getcachedservicespath ()))                    ->load ($this->config[' app.providers ');    }        Public Function Getcachedservicespath ()    {        return $this->bootstrappath (). ' /cache/services.php ';    }}

As you can see, all service providers are in the providers array of the configuration file app.php file. The Providerrepository class is responsible for all the service load functions:

Class providerrepository{public    function load (array $providers)    {        $manifest = $this->loadmanifest ();        if ($this->shouldrecompile ($manifest, $providers)) {            $manifest = $this->compilemanifest ($providers);        }        foreach ($manifest [' when '] as $provider = + $events) {            $this->registerloadevents ($provider, $events);        }        foreach ($manifest [' eager '] as $provider) {            $this->app->register ($provider);        }        $this->app->adddeferredservices ($manifest [' deferred ']);}    }

Loadmanifest () will load the service provider cache file services.php If the framework is first started without this file, or is a cache file in providers array entry with config/ Inconsistent providers array entries in the app.php will compile services.php.

//determine if you need to compile the build Services file Public function Shouldrecompile ($manifest, $providers ) {return is_null ($manifest) | | $manifest [' providers ']! = $providers;}    The specific procedure for compiling a makefile protected function compilemanifest ($providers) {$manifest = $this->freshmanifest ($providers);        foreach ($providers as $provider) {$instance = $this->createprovider ($provider); if ($instance->isdeferred ()) {foreach ($instance->provides () as $service) {$manifest [' De            Ferred '] [$service] = $provider;        } $manifest [' When '] [$provider] = $instance->when ();        } else {$manifest [' eager '] [] = $provider; }} return $this->writemanifest ($manifest);} protected function Freshmanifest (array $providers) {return [' providers ' = + $providers, ' eager ' = = [], ' deferred ' = = []];} 
    • In the cache file, providers is placed into all the custom and framework core services.

    • If the service provider needs to be registered immediately, it will be placed in the eager array in the cache file.

    • If the service provider is lazy-loaded, its function, provides (), typically provides a service alias, which is usually an alias registered with the service container, and the alias will be placed in the deferred array of the cache file, and a key-value pair is formed with the service provider that is actually being registered.

    • Deferred loading if activated by event events, you can write the event class in the When function and write to the when array of the cache file.

The resulting cache file contents are as follows:

Array (    ' providers ' = =     Array (      0 = ' Illuminate\\auth\\authserviceprovider ',      1 = ' Illuminate\\broadcasting\\broadcastserviceprovider ',      ...    ),    ' eager ' = =     Array (      0 = " Illuminate\\auth\\authserviceprovider ',      1 = ' Illuminate\\cookie\\cookieserviceprovider ',      ...    ) ,    ' deferred ' = =     Array (      ' illuminate\\broadcasting\\broadcastmanager ' = ' illuminate\\ ') Broadcasting\\broadcastserviceprovider ',      ' illuminate\\contracts\\broadcasting\\factory ' = ' Illuminate\\ ' Broadcasting\\broadcastserviceprovider ',      ...    ), ' when    ' = =     Array (      ' illuminate\\ Broadcasting\\broadcastserviceprovider ' = =       Array (      ),      ...)

Registering a deferred service provider when an event is triggered

In addition to using the IOC container parsing service mode activation, the deferred service provider can also be activated using the event events:

protected function registerloadevents ($provider, array $events) {    if (count ($events) < 1) {        return;    }    $this->app->make (' Events ')->listen ($events, function () use ($provider) {        $this->app->register ($ provider);}    );}

Instant Registration Service Provider

The Register method of the service provider that requires an instant registration is called by the application Register method:

Class Application extends Container implements Applicationcontract, httpkernelinterface{public Function register ($prov  Ider, $options = [], $force = False) {if ($registered = $this->getprovider ($provider)) &&! $force)        {return $registered;        } if (Is_string ($provider)) {$provider = $this->resolveprovider ($provider);        } if (Method_exists ($provider, ' Register ')) {$provider->register ();        } $this->markasregistered ($provider);        if ($this->booted) {$this->bootprovider ($provider);    } return $provider;        Public Function Getprovider ($provider) {$name = is_string ($provider)? $provider: Get_class ($provider); Return Arr::first ($this->serviceproviders, function ($value) use ($name) {return $value instanceof $n        Ame    }); The Public Function Resolveprovider ($provider) {return new $provider ($this);  } protected function markasregistered ($provider) {//This property will be used at a later time to booting service $this->serviceproviders[]        = $provider;       $this->loadedproviders[get_class ($provider)] = true;            } protected function Bootprovider (serviceprovider $provider) {if (Method_exists ($provider, ' boot ')) {        return $this->call ([$provider, ' Boot ']); }    }}

As you can see, the registration process for the service provider:

    • Determines whether the current service provider has been registered, such as registering a direct return object

    • Parsing service Providers

    • Call the service provider's register function

    • Flag The current service provider has been registered

    • If the framework has already loaded all the service containers that have been registered, then start the service provider's boot function, which is called by call, so it supports dependency injection.

Service parsing when registering a deferred service provider

The deferred service provider first needs to be added to the application

Public function adddeferredservices (array $services) {    $this->deferredservices = Array_merge ($this Deferredservices, $services);}

As we have said before, there are two ways to delay the activation registration of a service provider: event and service parsing.

When a specific event is fired, the register function of the application is called, and the Register function of the service provider is invoked to implement the registration of the service.

When using the Ioc container to parse the service name, such as parsing the service name Broadcastingfactory:

Class Broadcastserviceprovider extends serviceprovider{    protected $defer = true;        Public function provides ()    {        return [            broadcastmanager::class,            Broadcastingfactory::class,            Broadcastercontract::class,        ];    }}

In the application make method, the alias Broadcastingfactory is used to find out if there is a service provider for the deferred registration, and if so,
The service provider is registered first through the Registerdeferredprovider method.

Class Application extends Container implements Applicationcontract, httpkernelinterface{public    function make ($ Abstract)    {        $abstract = $this->getalias ($abstract);        if (Isset ($this->deferredservices[$abstract])) {            $this->loaddeferredprovider ($abstract);        }        Return Parent::make ($abstract);    }    Public Function Loaddeferredprovider ($service)    {        if (! isset ($this->deferredservices[$service])) {            return;        }        $provider = $this->deferredservices[$service];        if (! isset ($this->loadedproviders[$provider])) {            $this->registerdeferredprovider ($provider, $service);        }    }}

It is known by the deferredservices array that broadcastingfactory is a deferred service, and then the program uses the function Loaddeferredprovider to load the deferred service provider, invoking the service provider's register function, If the current framework has not yet registered the full service. Then it will be put into a service-initiated callback function to be called when the service starts:

Public Function Registerdeferredprovider ($provider, $service = null) {    if ($service) {        unset ($this deferredservices[$service]);    }    $this->register ($instance = new $provider ($this));    if (! $this->booted) {        $this->booting (function () use ($instance) {            $this->bootprovider ($instance);        });    }}

Or take the service provider Broadcastserviceprovider for example:

class Broadcastserviceprovider extends serviceprovider{protected $defer = True    ; Public Function Register () {$this->app->singleton (broadcastmanager::class, function ($app) {R        Eturn new Broadcastmanager ($app);        }); $this->app->singleton (Broadcastercontract::class, function ($app) {return $app->make (broadcastmanager        :: Class)->connection ();        }); Set Broadcastingfactory::class to alias of Broadcastmanager::class $this->app->alias (broadcastmanager::cl    , Broadcastingfactory::class); } public Function provides () {return [Broadcastmanager::class, BROADCASTINGFACTORY::C    Lass, Broadcastercontract::class,]; }}

The function register BroadcastingFactory binds a specific implementation class to the service container BroadcastManager , and Application the function in which it make executes parent::make($abstract) through the service container will parse the service correctly BroadcastingFactory .

Therefore provides() the element returned by the function must be a register() class name or alias that is bound to the service container. Thus, when we use App::make () to parse these class names, the service container will parse the service function correctly according to the implementation class that is bound in the register () function of the service provider.

Start Application

The startup of application is the responsibility of the class \Illuminate\Foundation\Bootstrap\BootProviders :

class bootproviders{Public Function bootstrap (application $app) {$app    ->boot ();        }}class Application extends Container implements Applicationcontract, httpkernelinterface{public Function boot () {        if ($this->booted) {return;        } $this->fireappcallbacks ($this->bootingcallbacks);        Array_walk ($this->serviceproviders, function ($p) {$this->bootprovider ($p);        });        $this->booted = true;    $this->fireappcallbacks ($this->bootedcallbacks);            } protected function Bootprovider (serviceprovider $provider) {if (Method_exists ($provider, ' boot ')) {        return $this->call ([$provider, ' Boot ']); }    }}

All service providers logged in the Serviceproviders attribute of the application application are called, that is, the boot method of the service provider is invoked, the boot is completed $this->booted = true and the application is Application formally started, and the request can be processed. In addition, the reason why you wait until all service providers are registered and then boot is because it is possible to invoke other service provider-registered services in a service provider's boot method, so wait until all the immediately registered service providers register to boot.

The above is the whole content of this article, I hope that everyone's learning has helped, more relevant content please pay attention to topic.alibabacloud.com!

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.