当前位置: 首页 > 后端技术 > PHP

LaravelServiceProvider开发中设置延迟加载遇到的问题

时间:2023-03-29 21:37:18 PHP

由于实际项目需求,最近在开发laravel-database-logger包时,发现将ServiceProvider的defer属性设置为true会导致在register方法中注册中间件无效。类ServiceProvider扩展\Illuminate\Support\ServiceProvider{protected$defer=true;publicfunctionregister(){$this->mergeConfigFrom(__DIR__.'/../config/config.php','ibrand.dblogger');$this->app->singleton(DbLogger::class,function($app){returnnewDbLogger();});//当$defer设置为true时,在路由中引用databaselogger中间件会报错,提示databaseloggerclassnotfound。$this->app[\Illuminate\Routing\Router::class]->middleware('databaselogger',Middleware::class);}publicfunctionprovides(){return[DbLogger::class];}}出现问题时,怀疑是将defer属性设置为true导致的。马上修改源码,把受保护的$defer=true;注释掉代码。结果还是提示databaseloggerclassnotfound.,说明Laravel没有注册接下来这个ServiceProvder正在思考如何解决这个问题,尝试了以下方法:1.验证代码本身没有问题注册你的在正常注册的AppServiceProvider中拥有自己的ServiceProviderpublicfunctionregister(){//$this->app->register(\Ibrand\DatabaseLogger\ServiceProvider::class);}注册后一切正常。2、config/app.php中provider注册无效,但在其他ServiceProvider中注册有效,说明其他问题。通过研究Illuminate\Foundation\Application的源码找到registerConfiguredProviders方法:Laravel在该方法中读取config/app.php中providers的内容,加载到ProviderRepository中。(newProviderRepository($this,newFilesystem,$this->getCachedServicesPath()))->load($providers->collapse()->toArray());关注$this->getCachedServicesPath(),通过源码发现Laravel根据bootstrap/cache/services.php文件决定如何注册ServiceProvider。这时候我想到了为什么//protected$defer=true;代码之前注释掉后还是无效。因此,为了让注释掉的//protected$defer=true;代码生效,需要执行phpartisanclear-compiledphpartisanoptimize,问题解决,对ServiceProvider的原理也有了更深的理解。所以记住:如果打算使用懒加载ServiceProvider,严禁注册中间件、路由等一系列操作。同时,更改defer属性值后,需要执行phpartisanclear-compiled和phpartisanoptimize更新ServiceProvider缓存。3、为什么在AppServiceProvider中注册有效?willing很简单,因为AppServiceProvider是不会延迟加载的,所以在AppServiceProvider中执行register方法注册一个新的ServiceProvider时,是不会延迟加载的。总结谨慎使用延迟加载ServiceProvider更改defer属性值后,需要执行phpartisanclear-compiled和phpartisanoptimize更新ServiceProvider缓存。严格禁止使用延迟加载的ServiceProvider注册中间件和路由。讨论