亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

laravel源碼分析隊(duì)列Queue方法示例

 更新時(shí)間:2022年04月05日 11:36:24   作者:immaxfang  
這篇文章主要為大家介紹了laravel源碼分析隊(duì)列Queue方法示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪<BR>

前言

隊(duì)列 (Queue) 是 laravel 中比較常用的一個(gè)功能,隊(duì)列的目的是將耗時(shí)的任務(wù)延時(shí)處理,比如發(fā)送郵件,從而大幅度縮短 Web 請(qǐng)求和響應(yīng)的時(shí)間。本文我們就來(lái)分析下隊(duì)列創(chuàng)建和執(zhí)行的源碼。

隊(duì)列任務(wù)的創(chuàng)建

先通過(guò)命令創(chuàng)建一個(gè) Job 類,成功之后會(huì)創(chuàng)建如下文件 laravel-src/laravel/app/Jobs/DemoJob.php。

> php artisan make:job DemoJob
 
> Job created successfully.

下面我們來(lái)分析一下 Job 類的具體生成過(guò)程。

執(zhí)行 php artisan make:job DemoJob 后,會(huì)觸發(fā)調(diào)用如下方法。

laravel-src/laravel/vendor/laravel/framework/src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php

/**
 * Register the command.
 * [A] make:job 時(shí)觸發(fā)的方法
 * @return void
 */
protected function registerJobMakeCommand()
{
    $this->app->singleton('command.job.make', function ($app) {
        return new JobMakeCommand($app['files']);
    });
}

接著我們來(lái)看下 JobMakeCommand 這個(gè)類,這個(gè)類里面沒(méi)有過(guò)多的處理邏輯,處理方法在其父類中。

?class JobMakeCommand extends GeneratorCommand

我們直接看父類中的處理方法,GeneratorCommand->handle(),以下是該方法中的主要方法。

public function handle()
{
    // 獲取類名
    $name = $this->qualifyClass($this->getNameInput());
    // 獲取文件路徑
    $path = $this->getPath($name);
    // 創(chuàng)建目錄和文件
    $this->makeDirectory($path);
    // buildClass() 通過(guò)模板獲取新類文件的內(nèi)容
    $this->files->put($path, $this->buildClass($name));
    // $this->type 在子類中定義好了,例如 JobMakeCommand 中 type = 'Job'
    $this->info($this->type.' created successfully.');
}

方法就是通過(guò)目錄和文件,創(chuàng)建對(duì)應(yīng)的類文件,至于新文件的內(nèi)容,都是基于已經(jīng)設(shè)置好的模板來(lái)創(chuàng)建的,具體的內(nèi)容在 buildClass($name) 方法中。

?protected function buildClass($name)
{
    // 得到類文件模板,getStub() 在子類中有實(shí)現(xiàn),具體看 JobMakeCommand 
    $stub = $this->files->get($this->getStub());
    // 用實(shí)際的name來(lái)替換模板中的內(nèi)容,都是關(guān)鍵詞替換
    return $this->replaceNamespace($stub, $name)->replaceClass($stub, $name);
}

獲取模板文件

protected function getStub()
{
    return $this->option('sync')
                    ? __DIR__.'/stubs/job.stub'
                    : __DIR__.'/stubs/job-queued.stub';
}

job.stub

?<?php
/**
* job 類的生成模板
*/
namespace DummyNamespace;
 
use Illuminate\Bus\Queueable;
use Illuminate\Foundation\Bus\Dispatchable;
 
class DummyClass
{
    use Dispatchable, Queueable;
 
    /**
     * Create a new job instance.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }
 
    /**
     * Execute the job.
     *
     * @return void
     */
    public function handle()
    {
        //
    }
}

job-queued.stub

<?php
/**
* job 類的生成模板
*/
namespace DummyNamespace;
 
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
 
class DummyClass implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
 
    /**
     * Create a new job instance.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }
 
    /**
     * Execute the job.
     *
     * @return void
     */
    public function handle()
    {
        //
    }
}

下面看一下前面我們創(chuàng)建的一個(gè)Job類,DemoJob.php,就是來(lái)源于模板 job-queued.stub。

<?php
/**
* job 類的生成模板
*/
namespace App\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
class DemoJob implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
 
    /**
     * Create a new job instance.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }
 
    /**
     * Execute the job.
     *
     * @return void
     */
    public function handle()
    {
        //
    }
}

至此,我們已經(jīng)大致明白了隊(duì)列任務(wù)類是如何創(chuàng)建的了。下面我們來(lái)分析下其是如何生效運(yùn)行的。

隊(duì)列任務(wù)的分發(fā)

任務(wù)類創(chuàng)建后,我們就可以在需要的地方進(jìn)行任務(wù)的分發(fā),常見(jiàn)的方法如下:

DemoJob::dispatch(); // 任務(wù)分發(fā)
DemoJob::dispatchNow(); // 同步調(diào)度,隊(duì)列任務(wù)不會(huì)排隊(duì),并立即在當(dāng)前進(jìn)程中進(jìn)行

下面先以 dispatch() 為例分析下分發(fā)過(guò)程。

trait Dispatchable
{
    public static function dispatch()
    {
        return new PendingDispatch(new static(...func_get_args()));
    }
}
?class PendingDispatch
{
    protected $job;
 
    public function __construct($job)
    {   echo '[Max] ' . 'PendingDispatch ' . '__construct' . PHP_EOL;
        $this->job = $job;
    }
    public function __destruct()
    {   echo '[Max] ' . 'PendingDispatch ' . '__destruct' . PHP_EOL;
        app(Dispatcher::class)->dispatch($this->job);
    }
}

重點(diǎn)是 app(Dispatcher::class)->dispatch($this->job) 這部分。

我們先來(lái)分析下前部分 app(Dispatcher::class),它是在 laravel 框架中自帶的 BusServiceProvider 中向 $app 中注入的。

class BusServiceProvider extends ServiceProvider implements DeferrableProvider
{
    public function register()
    {
        $this->app->singleton(Dispatcher::class, function ($app) {
            return new Dispatcher($app, function ($connection = null) use ($app) {
                return $app[QueueFactoryContract::class]->connection($connection);
            });
        });
    }
}

看一下 Dispatcher 的構(gòu)造方法,至此,我們已經(jīng)知道前半部分 app(Dispatcher::class) 是如何來(lái)的了。

class Dispatcher implements QueueingDispatcher
{
    protected $container;
    protected $pipeline;
    protected $queueResolver;
 
    public function __construct(Container $container, Closure $queueResolver = null)
    {
        $this->container = $container;
        /**
         * Illuminate/Bus/BusServiceProvider.php->register()中
         * $queueResolver 傳入的是一個(gè)閉包
         * function ($connection = null) use ($app) {
         *   return $app[QueueFactoryContract::class]->connection($connection);
         * }
         */
        $this->queueResolver = $queueResolver;
        $this->pipeline = new Pipeline($container);
    }
    public function dispatch($command)
    {
        if ($this->queueResolver && $this->commandShouldBeQueued($command)) {
        		// 將 $command 存入隊(duì)列
            return $this->dispatchToQueue($command);
        }
        return $this->dispatchNow($command);
    }
}

BusServiceProvider 中注冊(cè)了 Dispatcher::class ,然后 app(Dispatcher::class)->dispatch($this->job) 調(diào)用的即是 Dispatcher->dispatch()。

?public function dispatchToQueue($command)
{
    // 獲取任務(wù)所屬的 connection
    $connection = $command->connection ?? null;
    /*
     * 獲取隊(duì)列實(shí)例,根據(jù)config/queue.php中的配置
     * 此處我們配置 QUEUE_CONNECTION=redis 為例,則獲取的是RedisQueue
     * 至于如何通過(guò) QUEUE_CONNECTION 的配置獲取 queue ,此處先跳過(guò),本文后面會(huì)具體分析。
     */
    $queue = call_user_func($this->queueResolver, $connection);
    if (! $queue instanceof Queue) {
        throw new RuntimeException('Queue resolver did not return a Queue implementation.');
    }
    // 我們創(chuàng)建的DemoJob無(wú)queue方法,則不會(huì)調(diào)用
    if (method_exists($command, 'queue')) {
        return $command->queue($queue, $command);
    }
    // 將 job 放入隊(duì)列
    return $this->pushCommandToQueue($queue, $command);
}
protected function pushCommandToQueue($queue, $command)
{
    // 在指定了 queue 或者 delay 時(shí)會(huì)調(diào)用不同的方法,基本大同小異
    if (isset($command->queue, $command->delay)) {
        return $queue->laterOn($command->queue, $command->delay, $command);
    }
    if (isset($command->queue)) {
        return $queue->pushOn($command->queue, $command);
    }
    if (isset($command->delay)) {
        return $queue->later($command->delay, $command);
    }
    // 此處我們先看最簡(jiǎn)單的無(wú)參數(shù)時(shí)的情況,調(diào)用push()
    return $queue->push($command);
}

筆者的配置是 QUEUE_CONNECTION=redis ,估以此來(lái)分析,其他類型的原理基本類似。

配置的是 redis 時(shí), $queue 是 RedisQueue 實(shí)例,下面我們看下 RedisQueue->push() 的內(nèi)容。

Illuminate/Queue/RedisQueue.php

public function push($job, $data = '', $queue = null)
{
    /**
     * 獲取隊(duì)列名稱
     * var_dump($this->getQueue($queue));
     * 創(chuàng)建統(tǒng)一的 payload,轉(zhuǎn)成 json
     * var_dump($this->createPayload($job, $this->getQueue($queue), $data));
     */
    // 將任務(wù)和數(shù)據(jù)存入隊(duì)列
    return $this->pushRaw($this->createPayload($job, $this->getQueue($queue), $data), $queue);
}
public function pushRaw($payload, $queue = null, array $options = [])
{
    // 寫(xiě)入redis中
    $this->getConnection()->eval(
        LuaScripts::push(), 2, $this->getQueue($queue),
        $this->getQueue($queue).':notify', $payload
    );
    // 返回id
    return json_decode($payload, true)['id'] ?? null;
}

至此,我們已經(jīng)分析完了任務(wù)是如何被加入到隊(duì)列中的。

以上就是laravel源碼分析隊(duì)列Queue方法示例的詳細(xì)內(nèi)容,更多關(guān)于laravel源碼分析隊(duì)列Queue方法的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論