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-> ; 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!