laravel servie container源码解析

场景

  • service container是laravel的核心内容, 那么它到底是怎么实现的呢?

分析

  • 使用service container的方式有很多, 下面罗列几种
    • app(‘Illuminate\Hashing\BcryptHasher’)->make($password_source)
    • app(‘Illuminate\Contracts\Hashing\Hasher’)->make($password_source)
    • app(‘hash’)->make($password_source)
    • resolve(‘hash’)->make($password_source)
  • 其实本质都是调用Illuminate\Container\Container

app(‘Illuminate\Hashing\BcryptHasher’)具体实现

  • 从请求开始
    • index.php 实例化了Illuminate\Foundation\Application 它的__construct初始化几个比较重要的属性
      
      • protected $instances = []; The container’s shared instances.
      • protected $$aliases= []; The registered type aliases.
        • 结构 i n s t a n c e s [ instances[ instances[alias] = $abstract;
      • protected $abstractAliases = []; The registered aliases keyed by the abstract name.
        • 结构 a b s t r a c t A l i a s e s [ abstractAliases[ abstractAliases[abstract][] = $alias
    • app(‘Illuminate\Hashing\BcryptHasher’) 简单的跟踪下源码,就会发现调用Illuminate\Container\Container resolve方法;那它做了哪些工作呢?
      • $abstract = t h i s − > g e t A l i a s ( this->getAlias( this>getAlias(abstract);
      • if (isset( t h i s − > i n s t a n c e s [ this->instances[ this>instances[abstract]) && ! $needsContextualBuild) {}
        • $this->instances(第一步已经初始化过的) 中看看是否有值
        • 继续
      • $concrete = t h i s − > g e t C o n c r e t e ( this->getConcrete( this>getConcrete(abstract);
        • Get the concrete type for a given abstract.
        • 这段话很有意思, 如果我们没有提前去注册abstract 则我们将abstract变量当成要实例化的类的名称。 If we don't have a registered resolver or concrete for the type, we'll just assume each type is a concrete name and will attempt to resolve it as is since the container should be able to resolve concretes automatically.
        • 那么concrete到底是什么呢? 一般是service provider 使用 singleton bind注册的匿名函数;否则向上面所说的一样$abstract 本身假设成class name
        • 此时 $concrete = ‘Illuminate\Hashing\BcryptHasher’
      • t h i s − > i s B u i l d a b l e ( this->isBuildable( this>isBuildable(concrete, $abstract)
        • Determine if the given concrete is buildable.
        • 此时返回true
      • $object = $this->build($concrete);
      • if ( t h i s − > i s S h a r e d ( this->isShared( this>isShared(abstract) && ! $needsContextualBuild) {}
        • 判断是否要进行单例存储
      • t h i s − > f i r e R e s o l v i n g C a l l b a c k s ( this->fireResolvingCallbacks( this>fireResolvingCallbacks(abstract, $object);
        • Fire all of the resolving callbacks.
        • 这一步执行的是service provider boot方法
      • t h i s − > r e s o l v e d [ this->resolved[ this>resolved[abstract] = true;
        • 标记成已经解析过来的
加载依赖
 		$dependencies = $constructor->getParameters();

        // Once we have all the constructor's parameters we can create each of the
        // dependency instances and then use the reflection instances to make a
        // new instance of this class, injecting the created dependencies in.
        $instances = $this->resolveDependencies(
            $dependencies
        );

        array_pop($this->buildStack);

        return $reflector->newInstanceArgs($instances);
laravel内置的aliase表
[
            'app'                  => [\Illuminate\Foundation\Application::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],
            '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],
            '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\Contracts\Hashing\Hasher::class],
            'translator'           => [\Illuminate\Translation\Translator::class, \Illuminate\Contracts\Translation\Translator::class],
            'log'                  => [\Illuminate\Log\Writer::class, \Illuminate\Contracts\Logging\Log::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],
        ]
  • resove 源码
    /**
     * Resolve the given type from the container.
     *
     * @param  string  $abstract
     * @param  array  $parameters
     * @return mixed
     */
    protected function resolve($abstract, $parameters = [])
    {
        $abstract = $this->getAlias($abstract);
        $needsContextualBuild = ! empty($parameters) || ! is_null(
            $this->getContextualConcrete($abstract)
        );

        // If an instance of the type is currently being managed as a singleton we'll
        // just return an existing instance instead of instantiating new instances
        // so the developer can keep using the same objects instance every time.
        if (isset($this->instances[$abstract]) && ! $needsContextualBuild) {
            return $this->instances[$abstract];
        }
        $this->with[] = $parameters;

        $concrete = $this->getConcrete($abstract);
        // We're ready to instantiate an instance of the concrete type registered for
        // the binding. This will instantiate the types, as well as resolve any of
        // its "nested" dependencies recursively until all have gotten resolved.
        if ($this->isBuildable($concrete, $abstract)) {
            $object = $this->build($concrete);
        } else {
            $object = $this->make($concrete);
        }

        // If we defined any extenders for this type, we'll need to spin through them
        // and apply them to the object being built. This allows for the extension
        // of services, such as changing configuration or decorating the object.
        foreach ($this->getExtenders($abstract) as $extender) {
            $object = $extender($object, $this);
        }

        // If the requested type is registered as a singleton we'll want to cache off
        // the instances in "memory" so we can return it later without creating an
        // entirely new instance of an object on each subsequent request for it.
        if ($this->isShared($abstract) && ! $needsContextualBuild) {
            $this->instances[$abstract] = $object;
        }

        $this->fireResolvingCallbacks($abstract, $object);

        // Before returning, we will also set the resolved flag to "true" and pop off
        // the parameter overrides for this build. After those two things are done
        // we will be ready to return back the fully constructed class instance.
        $this->resolved[$abstract] = true;
        array_pop($this->with);

        return $object;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值