作为程序员一定要保持良好的睡眠,才能好编程

第十课 laravel服务容器及服务提供者介绍-provider

发布时间:2020-04-19

第十课 laravel服务容器及服务提供者介绍



服务容器:就是一个存放对象的空间   


为什么使用容器?  


IOC 控制反转       解决对象之间的依赖关系 的解耦   //降低代码之间的耦合度

                            控制反转的使用经常会和 DI 依赖注入一起实现。


Inversion of Control 控制反转


Dependency Injection DI   依赖注入,使用反射实现 。 使用容器中注册


laravel的容器是在哪里?

image.png




所有的服务提供者都会继承 ServiceProvides    


绑定容器 谁来做? 由服务提供者来做


服务提供者:编写说明。


如果没有继承任何接口,或父类就无需要注册到容器,等使用的时候,直接使用依赖注入即可使用。


例如:

public function tt(\App\Services\StudentService $stu) {

    echo $stu->eat();  

}


就是我们编写的服务没有继承、或者实现任何的接口文件,就可以使用依赖注入了。

那么没有继承任何接口是在说什么呢?




//定义了一个接口文件

namespace App\Contracts;
interface PeopleContracts{
public function say;
public function eat;
}



//学生服务类

namespace App\Services;
class StudentService extends ServiceProvides{
public function say(){
return '我是学生';
}
public function eat(){
return '每天去食堂吃饭';
}
}


//农民服务类

namespace App\Services;
class FarmerProvider extends ServiceProvides{
puclic function say(){
return '我是工人';
}
public function eat(){
return '我每天都要自己做饭';
}
}



服务类我们定义好了,那么如何注册到容器呢?


这其中有三种注册方法:


//单例模式

$this->app->singleton('People', function () {

    return new App\Services\StudentService();

});





//动态

$this->app->bind('People', function () {

    return new App\Services\StudentService();

});



//使用服务提供者进行绑定:


namespace App\Providers;
use App\Services\StudentService;
use Illuminate\Support\ServiceProvider;
class StudentProvider extends ServiceProvider{
  public function boot(){
  }
  public function register(){
    $this->app->singleton('People',function(){
        return new StudentService();
    });
  }
}



写好服务提供者后,在bootstrap/app.php 中 写入:


$app->register(App\Providers\StudentProvider::class);



=================================================




注意声明:在注册服务提供者的时候,首先会执行 register 方法,紧接着执行 boot() 方法,这是可据可查的。


服务提供者 register 这是首先要执行的方法,

再次boot 方法,其他自定义方法辅助这两个方法执行。


看下 src\Application.php  第180行

public function register($provider)
{
    if (! $provider instanceof ServiceProvider) {
        $provider = new $provider($this);
    }

    if (array_key_exists($providerName = get_class($provider), $this->loadedProviders)) {
        return;
    }

    $this->loadedProviders[$providerName] = true;
    
    
    //在这里判断了 register
    if (method_exists($provider, 'register')) {
        $provider->register();
    }

    //判断了boot 方法是否存在,如果存在就执行
    if (method_exists($provider, 'boot')) {
        return $this->call([$provider, 'boot']);
    }
}


-----------------------------------------

namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class MyServiceProvider extends ServiceProvider
{
  public function boot(){
    info('MyProvider write log服务 启动之后'.date('Y-m-d H:i:s')).microtime();
  }
  public function register(){
    info('hahahahhahahhahahah'.date('Y-m-d H:i:s')).microtime();
  }
}


-----------------------------------------


看看日志:

[2018-07-30 19:27:45] lumen.INFO: hahahahhahahhahahah2018-07-30 19:27:45  


[2018-07-30 19:27:45] lumen.INFO: MyProvider write log服务 启动之后2018-07-30 19:27:45  


==============================


如果准备采用延迟加载ServiceProvider时,严禁进行注册 middleware, route 等系列操作。

同时,更改 defer 属性值后,需要执行 php artisan clear-compiled 和 php artisan optimize 以更新 ServiceProvider 缓存。 


服务提供者 注册服务的时候,有两个方法:


register   在所有的服务提供者提供服务之前注册


boot 在所有服务加载之后进行注册的


这两种方式都是可以执行的。




providers 里面有一个  defer 设置为true  ,延迟加载。 当使用的时候才进行注册。


所有的服务都是在 config/app.php  中进行注册的。

里面有一个 providers 数组,在这个里面写就可以了。

当然了,还有一些是在框架中就定义好的。


例如: Illuminate\Foundation\Application 中的 registerCoreContainerAliases方法


public function registerCoreContainerAliases()
{
    foreach ([
        'app'                  => [self::class, \Illuminate\Contracts\Container\Container::class, \Illuminate\Contracts\Foundation\Application::class, \Psr\Container\ContainerInterface::class],
        'auth'                 => [\Illuminate\Auth\AuthManager::class, \Illuminate\Contracts\Auth\Factory::class],
        'auth.driver'          => [\Illuminate\Contracts\Auth\Guard::class],
        'blade.compiler'       => [\Illuminate\View\Compilers\BladeCompiler::class],
        'cache'                => [\Illuminate\Cache\CacheManager::class, \Illuminate\Contracts\Cache\Factory::class],
        'cache.store'          => [\Illuminate\Cache\Repository::class, \Illuminate\Contracts\Cache\Repository::class, \Psr\SimpleCache\CacheInterface::class],
        'cache.psr6'           => [\Symfony\Component\Cache\Adapter\Psr16Adapter::class, \Symfony\Component\Cache\Adapter\AdapterInterface::class, \Psr\Cache\CacheItemPoolInterface::class],
        'config'               => [\Illuminate\Config\Repository::class, \Illuminate\Contracts\Config\Repository::class],
        'cookie'               => [\Illuminate\Cookie\CookieJar::class, \Illuminate\Contracts\Cookie\Factory::class, \Illuminate\Contracts\Cookie\QueueingFactory::class],
        'encrypter'            => [\Illuminate\Encryption\Encrypter::class, \Illuminate\Contracts\Encryption\Encrypter::class],
        'db'                   => [\Illuminate\Database\DatabaseManager::class, \Illuminate\Database\ConnectionResolverInterface::class],
        'db.connection'        => [\Illuminate\Database\Connection::class, \Illuminate\Database\ConnectionInterface::class],
        'events'               => [\Illuminate\Events\Dispatcher::class, \Illuminate\Contracts\Events\Dispatcher::class],
        'files'                => [\Illuminate\Filesystem\Filesystem::class],
        'filesystem'           => [\Illuminate\Filesystem\FilesystemManager::class, \Illuminate\Contracts\Filesystem\Factory::class],
        'filesystem.disk'      => [\Illuminate\Contracts\Filesystem\Filesystem::class],
        'filesystem.cloud'     => [\Illuminate\Contracts\Filesystem\Cloud::class],
        'hash'                 => [\Illuminate\Hashing\HashManager::class],
        'hash.driver'          => [\Illuminate\Contracts\Hashing\Hasher::class],
        'translator'           => [\Illuminate\Translation\Translator::class, \Illuminate\Contracts\Translation\Translator::class],
        'log'                  => [\Illuminate\Log\LogManager::class, \Psr\Log\LoggerInterface::class],
        'mailer'               => [\Illuminate\Mail\Mailer::class, \Illuminate\Contracts\Mail\Mailer::class, \Illuminate\Contracts\Mail\MailQueue::class],
        'auth.password'        => [\Illuminate\Auth\Passwords\PasswordBrokerManager::class, \Illuminate\Contracts\Auth\PasswordBrokerFactory::class],
        'auth.password.broker' => [\Illuminate\Auth\Passwords\PasswordBroker::class, \Illuminate\Contracts\Auth\PasswordBroker::class],
        'queue'                => [\Illuminate\Queue\QueueManager::class, \Illuminate\Contracts\Queue\Factory::class, \Illuminate\Contracts\Queue\Monitor::class],
        'queue.connection'     => [\Illuminate\Contracts\Queue\Queue::class],
        'queue.failer'         => [\Illuminate\Queue\Failed\FailedJobProviderInterface::class],
        'redirect'             => [\Illuminate\Routing\Redirector::class],
        'redis'                => [\Illuminate\Redis\RedisManager::class, \Illuminate\Contracts\Redis\Factory::class],
        'request'              => [\Illuminate\Http\Request::class, \Symfony\Component\HttpFoundation\Request::class],
        'router'               => [\Illuminate\Routing\Router::class, \Illuminate\Contracts\Routing\Registrar::class, \Illuminate\Contracts\Routing\BindingRegistrar::class],
        'session'              => [\Illuminate\Session\SessionManager::class],
        'session.store'        => [\Illuminate\Session\Store::class, \Illuminate\Contracts\Session\Session::class],
        'url'                  => [\Illuminate\Routing\UrlGenerator::class, \Illuminate\Contracts\Routing\UrlGenerator::class],
        'validator'            => [\Illuminate\Validation\Factory::class, \Illuminate\Contracts\Validation\Factory::class],
        'view'                 => [\Illuminate\View\Factory::class, \Illuminate\Contracts\View\Factory::class],
    ] as $key => $aliases) {
        foreach ($aliases as $alias) {
            $this->alias($key, $alias);
        }
    }
}




门面模式:


门面模式注册在哪里注册的呢? 在 config/app.php  aliases 这样的一个数组

alias中注册所有的门面模式,里面一个  getFacadeAccessor 方法,方法里返回的字符串就是注册到容器中的服务名称,切记。


protected static function getFacadeAccessor()

{

    return 'log';

}




服务提供者 provider



/**
 * 获取提供商提供的服务
 * Get the services provided by the provider.
 *
 * @return array
 */
public function provides()
{
    return [];
}