laravel5.5源码阅读草稿——入口
laravel的启动需要通过路由、中间件、控制器、模型、视图最后出现在浏览器。而路由、中间件、模型,这些功能都有自己的类,比如Route::any()、DB::table()、$this->middleware()等等,这些功能都是由一个叫IOC(服务容器)的对象来调配的。
它就像框架里的一个管家,我们需要某些功能的时候不需要去自己new、去考虑运行这A对象还需要把哪些对象传入A对象里才能运行了。laravel的index入口文件只管制造一个ioc实例,然后把request对象传入其中。
ioc容器中有一个叫provider的概念,大多数功能都有一个provider,它的作用就是把一个功能需要用到的类,这些类的路径及所需要的一些东西记录起来,在ioc实例化的时候调用其中一些基础服务。ioc在实例化的时候,会把一些基础的provider调用起来,这些基础provider又调用了自身的初始化函数,来实现了一些自动化功能。
在public/index.php文件内,laravel首先加载了autoload方法,似乎是通过composer的方式实现的;
随后引入bootstrap/app.php文件,文件内实例化了application类,并通过该应用实例注册了Http、Kernel、Handler的共享绑定。
再看application类,继承自Container类,并继承了ApplicationContract接口(另一个application类,应该是实现了部分系统方法),与http核心接口(这里通过symfony的请求与响应类来实现接口)
插一张不知道从哪盗来的Application的继承关系图
在laravel把系统基础核心初始化完毕后,便通过application 的 make 方法,传入了http核心的类名来获取别名(在container类的aliases属性中,存储了众多类名与别名的键值对,似乎是通过类名到别名,再到实例的方式来获取的,数组见下方)
1 container->aliases 2 = 3 array:64 [▼ 4 "Illuminate\Foundation\Application" => "app" 5 "Illuminate\Contracts\Container\Container" => "app" 6 "Illuminate\Contracts\Foundation\Application" => "app" 7 "Psr\Container\ContainerInterface" => "app" 8 "Illuminate\Auth\AuthManager" => "auth" 9 "Illuminate\Contracts\Auth\Factory" => "auth" 10 "Illuminate\Contracts\Auth\Guard" => "auth.driver" 11 "Illuminate\View\Compilers\BladeCompiler" => "blade.compiler" 12 "Illuminate\Cache\CacheManager" => "cache" 13 "Illuminate\Contracts\Cache\Factory" => "cache" 14 "Illuminate\Cache\Repository" => "cache.store" 15 "Illuminate\Contracts\Cache\Repository" => "cache.store" 16 "Illuminate\Config\Repository" => "config" 17 "Illuminate\Contracts\Config\Repository" => "config" 18 "Illuminate\Cookie\CookieJar" => "cookie" 19 "Illuminate\Contracts\Cookie\Factory" => "cookie" 20 "Illuminate\Contracts\Cookie\QueueingFactory" => "cookie" 21 "Illuminate\Encryption\Encrypter" => "encrypter" 22 "Illuminate\Contracts\Encryption\Encrypter" => "encrypter" 23 "Illuminate\Database\DatabaseManager" => "db" 24 "Illuminate\Database\Connection" => "db.connection" 25 "Illuminate\Database\ConnectionInterface" => "db.connection" 26 "Illuminate\Events\Dispatcher" => "events" 27 "Illuminate\Contracts\Events\Dispatcher" => "events" 28 "Illuminate\Filesystem\Filesystem" => "files" 29 "Illuminate\Filesystem\FilesystemManager" => "filesystem" 30 "Illuminate\Contracts\Filesystem\Factory" => "filesystem" 31 "Illuminate\Contracts\Filesystem\Filesystem" => "filesystem.disk" 32 "Illuminate\Contracts\Filesystem\Cloud" => "filesystem.cloud" 33 "Illuminate\Contracts\Hashing\Hasher" => "hash" 34 "Illuminate\Translation\Translator" => "translator" 35 "Illuminate\Contracts\Translation\Translator" => "translator" 36 "Illuminate\Log\Writer" => "log" 37 "Illuminate\Contracts\Logging\Log" => "log" 38 "Psr\Log\LoggerInterface" => "log" 39 "Illuminate\Mail\Mailer" => "mailer" 40 "Illuminate\Contracts\Mail\Mailer" => "mailer" 41 "Illuminate\Contracts\Mail\MailQueue" => "mailer" 42 "Illuminate\Auth\Passwords\PasswordBrokerManager" => "auth.password" 43 "Illuminate\Contracts\Auth\PasswordBrokerFactory" => "auth.password" 44 "Illuminate\Auth\Passwords\PasswordBroker" => "auth.password.broker" 45 "Illuminate\Contracts\Auth\PasswordBroker" => "auth.password.broker" 46 "Illuminate\Queue\QueueManager" => "queue" 47 "Illuminate\Contracts\Queue\Factory" => "queue" 48 "Illuminate\Contracts\Queue\Monitor" => "queue" 49 "Illuminate\Contracts\Queue\Queue" => "queue.connection" 50 "Illuminate\Queue\Failed\FailedJobProviderInterface" => "queue.failer" 51 "Illuminate\Routing\Redirector" => "redirect" 52 "Illuminate\Redis\RedisManager" => "redis" 53 "Illuminate\Contracts\Redis\Factory" => "redis" 54 "Illuminate\Http\Request" => "request" 55 "Symfony\Component\HttpFoundation\Request" => "request" 56 "Illuminate\Routing\Router" => "router" 57 "Illuminate\Contracts\Routing\Registrar" => "router" 58 "Illuminate\Contracts\Routing\BindingRegistrar" => "router" 59 "Illuminate\Session\SessionManager" => "session" 60 "Illuminate\Session\Store" => "session.store" 61 "Illuminate\Contracts\Session\Session" => "session.store" 62 "Illuminate\Routing\UrlGenerator" => "url" 63 "Illuminate\Contracts\Routing\UrlGenerator" => "url" 64 "Illuminate\Validation\Factory" => "validator" 65 "Illuminate\Contracts\Validation\Factory" => "validator" 66 "Illuminate\View\Factory" => "view" 67 "Illuminate\Contracts\View\Factory" => "view" 68 ]
http_kernel 的 bings属性为container容器所绑定
kernel obj的回调函数为容器自身所创建,在创建过程中,将一些回调函数进行绑定,并触发,但在index页面第一次初始化时,并没有回调函数被绑定触发,obj创建的过程还是不清楚。创建出的kernel对象里存储的是系统初始化所需的各种中间件与服务供应者的类名全称,见下方
index文件返回的kernel核心只是app/http/kernel的对象。而kernel核心在实例化时,依赖了application与route两个对象。并将自身的$middlewareGroups、routeMiddleware数组解析进了route对象里,在路由进行调用的时候就会把路由方法上绑定的中间件名在这里解析出实例来调用了,其中routeMiddleware为别名所用。
在创建出kernel实例后,通过其父类的handle方法加载了provider的基类,其加载了bootstrap引导函数。
依次执行$bootstrappers中每一个bootstrapper的bootstrap()函数
$bootstrappers = [ 'Illuminate\Foundation\Bootstrap\DetectEnvironment', 'Illuminate\Foundation\Bootstrap\LoadConfiguration', 'Illuminate\Foundation\Bootstrap\ConfigureLogging', 'Illuminate\Foundation\Bootstrap\HandleExceptions', 'Illuminate\Foundation\Bootstrap\RegisterFacades', 'Illuminate\Foundation\Bootstrap\RegisterProviders', 'Illuminate\Foundation\Bootstrap\BootProviders', ];
上面bootstrap中会分别执行每一个bootstrapper的bootstrap方法来引导启动应用程序的各个部分
1. DetectEnvironment 检查环境
2. LoadConfiguration 加载应用配置
3. ConfigureLogging 配置日至
4. HandleException 注册异常处理的Handler
5. RegisterFacades 注册Facades
6. RegisterProviders 注册Providers
7. BootProviders 启动Providers
启动应用程序的最后两步就是注册服务提供者和启动提供者,先来看注册服务提供器,服务提供器的注册由类\Illuminate\Foundation\Bootstrap\RegisterProviders::class负责,该类用于加载所有服务提供器的 register 函数,并保存延迟加载的服务的信息,以便实现延迟加载。
所有服务提供器都在配置文件 app.php 文件的 providers 数组中。类 ProviderRepository 负责所有的服务加载功能:
loadManifest()会加载服务提供器缓存文件services.php,如果框架是第一次启动时没有这个文件的,或者是缓存文件中的providers数组项与config/app.php里的providers数组项不一致都会编译生成services.php。
Illuminate\Foundation\Http\Kernel 的 dispatchToRouter 方法返回的闭包函数里包含了调用请求的代码。这段代码指向了Illuminate\Routing\router类
Illuminate\Routing\Route类的runCallable方法里对路由进行了调用
控制器和方法是从路由文件中获取到的(通过symfony的request对象获取到pathinfo),依然是通过字符串解析为类名和方法名,随后通过ioc容器实例化类为对象,再调用控制器基类的某个方法执行传入的方法名
Illuminate\Routing\ControllerDispatcher类的dispatch方法为真正执行的部分
插一张流程图