Lumen是基于Laravel框架,专注于后端微服务、无状态API开发的框架。
Laravel生命周期有完整的文档描述:Laravel Request lifecycle
Lumen官方缺少对其完成生命周期的文档说明,故展开说明下。
Lumen lifecycle生命周期
从源码依次入手,逐级跟踪调用关系,列表如下:
- Lumen程序入口:public/index.php
- 加载bootstrap/app.php:
$app = require __DIR__.'/../bootstrap/app.php';
- 执行容器的run():
$app->run();
- 加载bootstrap/app.php:
- 文件bootstrap/app.php中所进行操作:
- 加载vendor目录自动加载文件:
require_once __DIR__.'/../vendor/autoload.php';
, 这是composer默认自动加载文件。 - 加载.env配置:
(new Dotenv\Dotenv(__DIR__.'/../'))->load()
,Lumen采用.env接管配置,此处进行配置加载。 - 生成容器$app:
$app = new Laravel\Lumen\Application()
, 其实Laravel/Lumen的核心就是容器,再看Application源码也是继承了Container。 - 启动Facades特性:
$app->withFacades();
, Lumen默认是禁用了Facades特性,取消注释则启用。 - 启用Eloquent特性:
$app->withEloquent();
, Lumen默认禁用了Eloquent的ORM支持,作者说是给用户自行选择不同ORM的权利。 - 加载配置文件:
$app->configure('app');
, 如果有自定义的配置文件,则需要在此进行加载。 - 注册容器绑定:
$app->singleton()
, 看过源码singleton和bind区别就是前者内部调用了bind,且第三个参数设为true,意思是共享、独一的对象,也就是单例模式。 - 注册中间件:
$app->middleware
, 根据需要添加或去除注释启用。 - 注册ServiceProvider:
$app->register(App\Providers\LogServiceProvider::class);
, Laravel/Lumen的很大一部分特性是依赖ServiceProvider实现的。 - 加载路由文件:
$app->group()
, 这里可以再跟下group()的实现,在vendor/laravel/lumen-framework/src/Concerns/RoutesRequests.php
中。 - 返回容器$app
整个过程描述图示如下:
- 加载vendor目录自动加载文件:
注: 这里用到了PHP trait,参考PHP oop Traits。
Laravel/Lumen 容器/ServiceProvider
Facades 模式
中文译名:外观模式、门面模式。
主要特性:屏蔽内部实现,开放接口供外部使用,提高模块抽象。
Laravel中的Facades也是在框架级提供抽象调用,从而使开发者无需关心内容实现。
Facades的理解:
别名,首先通过class_alias将DB、Log、Cache等关键词映射为不同的Facade类。
1
class_alias('Illuminate\Support\Facades\Cache', 'Cache');
不同Facade子类返回容器内注册服务的关键词: db、log、cache等。
1
2
3
4
5
6
7
8
9
10
11
12class Cache extends Facade
{
/**
* Get the registered name of the component.
*
* @return string
*/
protected static function getFacadeAccessor()
{
return 'cache';
}
}通过不同世纪的绑定函数,向容器中注册或绑定service provider.
1
2
3
4
5
6
7
8
9protected function registerCacheBindings()
{
$this->singleton('cache', function () {
return $this->loadComponent('cache', 'Illuminate\Cache\CacheServiceProvider');
});
$this->singleton('cache.store', function () {
return $this->loadComponent('cache', 'Illuminate\Cache\CacheServiceProvider', 'cache.store');
});
}
Facades主要依赖Service Container和Service Provider实现。
注1:推荐一篇文章对容器介绍很全面:laravel 学习笔记 —— 神奇的服务容器
注2: Laravel容器的思想很巧妙,可以仔细阅读上篇文章,结合源码学习,相信有很多收获。
ServiceContainer
其实就是$app
, 它是全局的一个容器,是Laravel的核心。
容器(Service Container)实现:vendor/laravel/lumen-framework/src/Application.php1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17class Application extends Container
{
use Concerns\RoutesRequests,
Concerns\RegistersExceptionHandlers;
public function withEloquent()
public function withFacades()
public function make($abstract, array $parameters = [])
public function configure($name)
public function register($provider, $options = [], $force = false)
protected function registerCacheBindings()
protected function registerDatabaseBindings()
protected function registerEncrypterBindings()
protected function registerLogBindings()
//////////////////////////////////
// 各种Service Provider的绑定
//////////////////////////////////
}
ServiceProvider
向容器提供不同的服务,通过register函数向容器中注入类实例,从而实现DI(依赖注入),是一种IOC的实现方式。
不同服务的ServiceProvider分布在不同的服务子目录下:
- cache: vendor/illuminate/cache/CacheServiceProvider.php
- db: vendor/illuminate/database/DatabaseServiceProvider.php
queue: vendor/illuminate/queue/QueueServiceProvider.php
不同的ServiceProvider都继承ServiceProvider;
- 重写register()方法;
- $defer变量表征是否延迟加载;
- provides()方法返回该ServiceProvider可向容器提供的所有服务列表;
总结
本文大致梳理了Laravel/Lumen中Facade, Service Container, Service Provider的不同概念、实现逻辑和调用关系。
Laravel框架的思想:采用容器的方式管理通用功能,实现IOC控制反转,解决依赖注入问题。
其实,只采用Service Provider的方式,在bootstrap/app.php中进行服务注册,在需要的使用调用$app->make(‘db’)的方式也是可行的。
Facades更多的是最大化减少程序依赖,提供一体化的编程体验,这也是Laravel优雅之美。