服务提供者是 Laravel 应用启动的中心,你自己的应用以及所有 Laravel 的核心服务都是通过服务提供者启动。但是,我们所谓的「启动」指的是什么?通常,这意味着注册服务,包括注册服务容器绑定、事件监听器、中间件甚至路由。服务提供者是应用配置的中心。
有了上面的依赖注入和服务容器,对于服务提供者来说,就非常好理解了,先来看一下Laravel自带的服务提供者AppServiceProvider
class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
}
/**
* Register any application services.
*
* @return void
*/
public function register()
{
}
}
其中含有两个方法,register()和boot()这两个方法一个是注册,一个是启动初始化, 通过阅读源码,我们来查看Laravel是怎么运行这两个方法的
//Illuminate/Foundation/Application.php
public function __construct($basePath = null)
{
if ($basePath) {
$this->setBasePath($basePath);
}
$this->registerBaseBindings(); //绑定一些基本变量
$this->registerBaseServiceProviders(); //注册服务
$this->registerCoreContainerAliases(); //注册别名
}
//Illuminate/Foundation/Application.php
protected function registerBaseServiceProviders()
{
$this->register(new EventServiceProvider($this));
$this->register(new LogServiceProvider($this));
$this->register(new RoutingServiceProvider($this));
}
//Illuminate/Foundation/Application.php
public function register($provider, $options = [], $force = false)
{
//如果服务已经进行了注册,就直接返回
if (($registered = $this->getProvider($provider)) && ! $force) {
return $registered;
}
// If the given "provider" is a string, we will resolve it, passing in the
// application instance automatically for the developer. This is simply
// a more convenient way of specifying your service provider classes.
//如果是个字符串,进行实例化
if (is_string($provider)) {
$provider = $this->resolveProvider($provider);
}
//如果存在register方法则进行调用
//我们上面的AppServiceProvider方法中含有register方法,因此register方法会在这里进行执行
if (method_exists($provider, 'register')) {
$provider->register();
}
//生成缓存文件
$this->markAsRegistered($provider);
// If the application has already booted, we will call this boot method on
// the provider class so it has an opportunity to do its boot logic and
// will be ready for any usage by this developer's application logic.
// 如果应用已经启动了,即代表所有需要加载的服务提供者都已经进行了启动,可以执行boot方法
if ($this->booted) {
$this->bootProvider($provider);
}
//返回服务提供者
return $provider;
}
通过上面的方法我们已经知道了,服务提供者的加载方式,那其他的服务提供者Laravel是怎么进行加载的呢?我们继续来看代码
//public/index.php
$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);
//执行handler方法
$response = $kernel->handle(
$request = Illuminate\Http\Request::capture()
);
//src/Illuminate/Foundation/Http/Kernel.php
public function handle($request)
{
try {
$request->enableHttpMethodParameterOverride();
//主要查看这个流程
$response = $this->sendRequestThroughRouter($request);
} catch (Exception $e) {
$this->reportException($e);
$response = $this->renderException($request, $e);
} catch (Throwable $e) {
$this->reportException($e = new FatalThrowableError($e));
$response = $this->renderException($request, $e);
}
$this->app['events']->dispatch(
new Events\RequestHandled($request, $response)
);
return $response;
}
//src/Illuminate/Foundation/Http/Kernel.php
protected function sendRequestThroughRouter($request)
{
$this->app->instance('request', $request);
Facade::clearResolvedInstance('request');
//在这里执行了bootstrap()启动方法
$this->bootstrap();
return (new Pipeline($this->app))
->send($request)
->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware)
->then($this->dispatchToRouter());
}
//src/Illuminate/Foundation/Http/Kernel.php
public function bootstrap()
{
/*执行了这些服务提供者
protected $bootstrappers = [
\Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables::class,
\Illuminate\Foundation\Bootstrap\LoadConfiguration::class,
\Illuminate\Foundation\Bootstrap\HandleExceptions::class,
\Illuminate\Foundation\Bootstrap\RegisterFacades::class,
\Illuminate\Foundation\Bootstrap\RegisterProviders::class,
\Illuminate\Foundation\Bootstrap\BootProviders::class,
];
*/
if (! $this->app->hasBeenBootstrapped()) {
$this->app->bootstrapWith($this->bootstrappers());
}
}
//在上面注册了RegisterProviders,我们看看他的逻辑
//Illuminate/Foundation/Bootstrap/RegisterProviders.php
public function bootstrap(Application $app)
{
$app->registerConfiguredProviders();
}
//Illuminate/Foundation/Application.php
public function registerConfiguredProviders()
{
//在这里加载了app.providers中的所有服务提供者
$providers = Collection::make($this->config['app.providers'])
->partition(function ($provider) {
return Str::startsWith($provider, 'Illuminate\\');
});
$providers->splice(1, 0, [$this->make(PackageManifest::class)->providers()]);
(new ProviderRepository($this, new Filesystem,
//load服务提供者
$this->getCachedServicesPath()))
->load($providers->collapse()->toArray());
}
//Illuminate/Foundation/ProviderRepository.php
public function load(array $providers)
{
//加载缓存
$manifest = $this->loadManifest();
// First we will load the service manifest, which contains information on all
// service providers registered with the application and which services it
// provides. This is used to know which services are "deferred" loaders.
if ($this->shouldRecompile($manifest, $providers)) {
$manifest = $this->compileManifest($providers);
}
// Next, we will register events to load the providers for each of the events
// that it has requested. This allows the service provider to defer itself
// while still getting automatically loaded when a certain event occurs.
//事件加载
foreach ($manifest['when'] as $provider => $events) {
$this->registerLoadEvents($provider, $events);
}
// We will go ahead and register all of the eagerly loaded providers with the
// application so their services can be registered with the application as
// a provided service. Then we will set the deferred service list on it.
//立即加载
foreach ($manifest['eager'] as $provider) {
$this->app->register($provider);
}
//写入数组中
$this->app->addDeferredServices($manifest['deferred']);
}
//Illuminate/Foundation/ProviderRepository.php
protected function compileManifest($providers)
{
// The service manifest should contain a list of all of the providers for
// the application so we can compare it on each request to the service
// and determine if the manifest should be recompiled or is current.
$manifest = $this->freshManifest($providers);
foreach ($providers as $provider) {
$instance = $this->createProvider($provider);
// When recompiling the service manifest, we will spin through each of the
// providers and check if it's a deferred provider or not. If so we'll
// add it's provided services to the manifest and note the provider.
if ($instance->isDeferred()) {
//如果需要延迟加载,放入deffered队列中
foreach ($instance->provides() as $service) {
$manifest['deferred'][$service] = $provider;
}
//如果需要事件加载,放入when
$manifest['when'][$provider] = $instance->when();
}
// If the service providers are not deferred, we will simply add it to an
// array of eagerly loaded providers that will get registered on every
// request to this application instead of "lazy" loading every time.
else {
//立即加载
$manifest['eager'][] = $provider;
}
}
return $this->writeManifest($manifest);
}
//Illuminate/Foundation/Application.php
public function bootstrapWith(array $bootstrappers)
{
$this->hasBeenBootstrapped = true;
foreach ($bootstrappers as $bootstrapper) {
//注册事件
$this['events']->fire('bootstrapping: '.$bootstrapper, [$this]);
//获取到类,执行bootstarp()方法
$this->make($bootstrapper)->bootstrap($this);
$this['events']->fire('bootstrapped: '.$bootstrapper, [$this]);
}
}
//Illuminate/Foundation/Application.php
public function make($abstract, array $parameters = [])
{
$abstract = $this->getAlias($abstract);
//延迟绑定
if (isset($this->deferredServices[$abstract]) && ! isset($this->instances[$abstract])) {
$this->loadDeferredProvider($abstract);
}
//执行make方法,获取实例
return parent::make($abstract, $parameters);
}
public function registerDeferredProvider($provider, $service = null)
{
// Once the provider that provides the deferred service has been registered we
// will remove it from our local list of the deferred services with related
// providers so that this container does not try to resolve it out again.
if ($service) {
unset($this->deferredServices[$service]);
}
//延迟加载
$this->register($instance = new $provider($this));
//如果服务还未加载,放入到boot中进行加载
if (! $this->booted) {
$this->booting(function () use ($instance) {
$this->bootProvider($instance);
});
}
}
//上面还注册了BootProviders服务,他的源码相对来说简单
public function boot()
{
if ($this->booted) {
return;
}
// Once the application has booted we will also fire some "booted" callbacks
// for any listeners that need to do work after this initial booting gets
// finished. This is useful when ordering the boot-up processes we run.
$this->fireAppCallbacks($this->bootingCallbacks);
//调用
array_walk($this->serviceProviders, function ($p) {
$this->bootProvider($p);
});
$this->booted = true;
$this->fireAppCallbacks($this->bootedCallbacks);
}
服务提供者的流程我们大概进行了了解,接下来我们来看看怎么获取到服务提供者,这里Laravel使用了门面模式,大家有兴趣的话,可以先了解下门面模式 blog.csdn.net/qq_29058883…