老司机带你深入 Laravel 之 ServiceProvider 原理

生活的感慨

生活中的朋友不需要太多,有那么几个就可以了,去关心那些真心关心你的人,至于其他人嘛,都是路人,不要把那些真心关心你的人,当成一坨屎,他们都是你最为宝贵的财富。温文尔雅,不卑不亢,无论是遇到漂亮的姑娘还是公司的领导,都要波澜不惊,自然优雅。

博文简介

在今天的这一篇博文中,我会带领大家深入的学习ServiceProvider,为什么要讲这个,我们来看官方的文档结构。

老司机带你深入Laravel之ServiceProvider

Laravel官方在架构理念这里把它列出来,所以ServiceProvider的重要性,就不言而喻了,但是,今天在这里我不打算讲Laravel的基础用法,如果你不清楚这块的内容,你可以参考官方文档, Laravel之ServiceProvider,我今天要讲的是,Laravel是如何引导和加载ServiceProvider的。

阅读基础

在阅读这篇博文之前,希望你已经知道如何使用ServiceProvider,这个我在上面讲过了。

一定要阅读我的上一篇博文, 老司机带你深入理解 Laravel 之 Facade,这不是在开玩笑,我不想再讲我已经讲过的东西,希望你对自己负责,不然的话,我觉得你没有必要再阅读下面的内容了,浪费自己的时间,有这个时间还不如干点儿正事。

深入源代码

在类Illuminate\Foundation\Http\Kernel类的bootstrappers属性中,如下:
老司机带你深入Laravel之ServiceProvider

我们只关心\Illuminate\Foundation\Bootstrap\RegisterProviders::class这个类,在这里Laravel会加载所有的ServiceProvider,下面我们进入到它的bootstrap方法中:

老司机带你深入Laravel之ServiceProvider

可以看到它的bootstrap方法很简单,这里直接调用了Application类的registerConfiguredProviders方法,这个方法如下所示:

老司机带你深入Laravel之ServiceProvider

上面的代码你看不懂没关系,我仔细给你解释下,在这之前,我提醒大家,去看看Collection类的使用,估计很多人没使用过,真的很好用,$this->config['app.providers']就是你在config/app.php的providers属性中所定义的所有的ServiceProvider,Collection的partition方法会使用它的回调参数,重新生成一个只有2个元素的Collection对象,2个子元素都是Collection类的对象,第一个子元素包含的都是Laravel自身定义的ServiceProvider,第二个Collection包含了我们自己定义的ServiceProvider和第三方包定义的,这里的PackageManifest::class的providers方法会返回Composer包定义的,至于为啥是这样,建议你去看我在 老司机带你深入理解 Laravel 之 Facade中的说明,不再陈述。Collection类的splice方法将其它包定义的provider加入到当前容器中。Application类的getCachedServicesPath方法返回缓存的路径,这个路径指的是啥呢?就是下面这个:

老司机带你深入Laravel之ServiceProvider

这是一个缓存文件,记录了当前系统所有的ServiceProvider,你一定要去看一下这个文件,文件的结构一目了然。
ProviderRepository这个类很简单,我们的ServiceProvider就是在这个类中进行加载的,下面我们来看它的load方法,它的参数就是系统所有的ServiceProvider。

老司机带你深入Laravel之ServiceProvider

首先调用loadManifest方法,这个方法很简单,它的作用就是加载项目根目录下面的bootstrap\cache\packages.php文件,就是我上面的截图,上面说了这是一个缓存文件,回到load方法中,继续调用shouldRecompile方法,这个方法会比较当前所有的ServiceProvider和之前缓存的ServiceProvider是否是相等的,如果相等,也就是说我们可以忽略编译的过程,这里我们假设缓存失效或者是不存在,那么compileManifest方法就会被调用,开始编译所有的ServiceProvider,下面是这个方法的代码:

老司机带你深入Laravel之ServiceProvider

首先调用freshManifest方法,freshManifest方法很简单,如下:

老司机带你深入Laravel之ServiceProvider

紧接着遍历所有的ServiceProvider,createProvider会创建对应ServiceProvider类的对象,在这里我们要提一句,就是Laravel中,所有的ServiceProvider都继承自Illuminate\Support\ServiceProvider类。Illuminate\Support\ServiceProvider类有一个方法isDeferred,表示当前的ServiceProvider是延迟的还是非延迟的,如果ServiceProvider的话,它的register方法不会马上被调用,相反,此时的ServiceProvider应该提供provides方法,我们打开bootstrap/cache/services.php文件可以看到,Laravel中存在很多的ServiceProvider是延迟的,截图如下:

老司机带你深入Laravel之ServiceProvider

打开Illuminate\Cache\CacheServiceProvider文件,它的provides方法如下:

老司机带你深入Laravel之ServiceProvider

所以如果以后,你从容器里面获取cache,cache.store或者是memcached.connector的时候,都会导致CacheServiceProvider的register方法被调用,这也就是延迟ServiceProvider的由来。回到compileManifest方法中,它会遍历provides方法的返回结果,并且把它存储到$manifest数组中,$manifest数组的格式和freshManifest方法返回的是一样的,上面的截图已经说明一切。$manifest['when']记录事件,这个我们很少用到,暂不分析它,继续往下走
,如果ServiceProvider不是延迟的,那么把它加入到$manifest['eager']数组中,最后调用writeManifest方法把$manifest写入到bootstrap/cache/services.php缓存文件中。好了,compileManifest方法分析完了,我们回到load方法中:

老司机带你深入Laravel之ServiceProvider

$manifest['eager']中存储的provider是需要立即被注册的,这里的Application类的register方法被调用,这个方法是专门用于注册ServiceProvider的,这个函数我已经在 老司机带你深入理解 Laravel 之 Facade讲过了,大家不记得可以回去看一下,主要就是ServiceProvider的register方法被调用。回到load方法中,Application的addDeferredServices方法被调用,该方法很简单:

老司机带你深入Laravel之ServiceProvider

到这里为止,ServiceProvider的加载基本讲完了,但是你是否还有疑惑,就是延迟的ServiceProvider是什么时候加载的,下面我们来看一下,Application重写了Container的make方法:

老司机带你深入Laravel之ServiceProvider

这里首先判断需要加载的服务是不是属于延迟ServiceProvider的,如果是的话,loadDeferredProvider方法被调用,如下:

老司机带你深入Laravel之ServiceProvider

这个放调用到了registerDeferredProvider方法,如下:

老司机带你深入Laravel之ServiceProvider

这段代码是不是很熟悉,我就不再解释了。

如果你自己写过ServiceProvider的话,那么你可能会实现boot方法,这个方法是啥时候被调用的呢?还记得这张图么?
老司机带你深入Laravel之ServiceProvider

这里的BootProviders就是这里的关键,它的bootstrap方法如下:

老司机带你深入Laravel之ServiceProvider

Application的boot方法,如下:

老司机带你深入Laravel之ServiceProvider

boot方法调用bootProvide方法,如下:

老司机带你深入Laravel之ServiceProvider

这里检查如果你的ServiceProvider实现了boot方法,那么就会调用,到这里位置Laravel的ServiceProvider就讲解完毕了,如果你存在疑惑或者是需要帮助,可以加这个群:

总结

没有人天生就能够读懂复杂的代码,你需要的是耐心和对成功的渴望,不要给自己退缩的理由,你真的可以,我觉得你也应该这么做。

laravel php serviceprovider
本作品采用 《CC 协议》,转载必须注明作者和本文链接
微信:okayGoHome
本帖由系统于 4年前 自动加精
Dennis_Ritchie
26 人点赞
《L01 基础入门》
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《G01 Go 实战入门》
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 9
lochpure

:+1:

4年前 评论
FamousMai

火前留言

4年前 评论
outnull

支持 期待更多优质文章

4年前 评论
avrilko

貌似在b站看到一个老哥的laravel视频

4年前 评论
Yoger

看完,内心好舒服

4年前 评论
Tyzito

:+1: :+1:

4年前 评论
zpers

每看一遍理解都有所加深

4年前 评论
startToNow

细细看了一遍,写的很好

4年前 评论
gutao123

写的太棒了!

2年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!
Dennis_Ritchie
Golang,Rust,K8s,Docker,Rust,C/C++,数据库爱好者,操作系统爱好者 @ Coder
文章
32
粉丝
892
喜欢
1253
收藏
1064
排名:55
访问:13.6 万
私信
所有博文
博客标签
auth
1
php
21
laravel
14
javascript
1
reflection
1
form
1
validator
2
pipeline
1
view
1
Socket
3
websocket
1
base64
1
serviceprovider
1
slice
1
中间件
1
算法
1
数据结构
1
缓存
1
二叉树
1
设计模式
2
容器
1
反射
1
路由
3
授权
1
切片
1
管道
1
编程心得
9
源代码
8
验证器
2
老司机
1
社区赞助商
成为赞助商

玻璃钢生产厂家宝鸡市玻璃钢雕塑厂家公园玻璃钢卡通雕塑厂家现货深圳市永锋玻璃钢工程雕塑厂石家庄定制玻璃钢雕塑制作长沙玻璃钢景观雕塑厂家商场网红美陈布置玻璃钢花盆组合供应商常州动物玻璃钢雕塑公司商场开业美陈收费标准新乡玻璃钢浮雕不锈钢雕塑公司玻璃钢树脂乐高雕塑广州树脂玻璃钢雕塑生产商安庆户内玻璃钢雕塑哪家便宜凉山玻璃钢花盆花器开学季商场美陈陕西现代人物玻璃钢雕塑商丘不锈钢玻璃钢彩绘雕塑厂家乐山玻璃钢艺术雕塑厂玻璃钢雕塑人物公司云南玻璃钢花盆哪里有德宏玻璃钢雕塑订购长春人物玻璃钢雕塑厂家阜阳制作玻璃钢雕塑厂报价表河南玻璃钢雕塑介绍天津吉林玻璃钢雕塑玻璃钢园林雕塑小品安装金元宝玻璃钢雕塑玻璃钢雕塑展览怎么样河北玻璃钢龙雕塑厂家贵阳玻璃钢雕塑加工厂香港通过《维护国家安全条例》两大学生合买彩票中奖一人不认账让美丽中国“从细节出发”19岁小伙救下5人后溺亡 多方发声单亲妈妈陷入热恋 14岁儿子报警汪小菲曝离婚始末遭遇山火的松茸之乡雅江山火三名扑火人员牺牲系谣言何赛飞追着代拍打萧美琴窜访捷克 外交部回应卫健委通报少年有偿捐血浆16次猝死手机成瘾是影响睡眠质量重要因素高校汽车撞人致3死16伤 司机系学生315晚会后胖东来又人满为患了小米汽车超级工厂正式揭幕中国拥有亿元资产的家庭达13.3万户周杰伦一审败诉网易男孩8年未见母亲被告知被遗忘许家印被限制高消费饲养员用铁锨驱打大熊猫被辞退男子被猫抓伤后确诊“猫抓病”特朗普无法缴纳4.54亿美元罚金倪萍分享减重40斤方法联合利华开始重组张家界的山上“长”满了韩国人?张立群任西安交通大学校长杨倩无缘巴黎奥运“重生之我在北大当嫡校长”黑马情侣提车了专访95后高颜值猪保姆考生莫言也上北大硕士复试名单了网友洛杉矶偶遇贾玲专家建议不必谈骨泥色变沉迷短剧的人就像掉进了杀猪盘奥巴马现身唐宁街 黑色着装引猜测七年后宇文玥被薅头发捞上岸事业单位女子向同事水杯投不明物质凯特王妃现身!外出购物视频曝光河南驻马店通报西平中学跳楼事件王树国卸任西安交大校长 师生送别恒大被罚41.75亿到底怎么缴男子被流浪猫绊倒 投喂者赔24万房客欠租失踪 房东直发愁西双版纳热带植物园回应蜉蝣大爆发钱人豪晒法院裁定实锤抄袭外国人感慨凌晨的中国很安全胖东来员工每周单休无小长假白宫:哈马斯三号人物被杀测试车高速逃费 小米:已补缴老人退休金被冒领16年 金额超20万

玻璃钢生产厂家 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化