Частичный анализ исходного кода XXl-job

Java

предисловие

Текст был включен в мой репозиторий GitHub, добро пожаловать в Star: https://github.com/bin392328206/six-finger
Лучшее время посадить дерево было десять лет назад, затем сейчас
Поощряйте всех вести блог на пути к технологиям

болтовня

Поскольку я много раз использовал xxl-job, а затем я также изменил его пограничный бизнес-код на соответствующее использование его компании, например, наши динамические задачи синхронизации, интерфейсы вызовов и т. д., но соответствующие его основному исходному коду, я не не было возможности разобраться, найду время разобраться вместе, но что хочу сказать, так это то, что эта статья о трактовке принципа, не подходящего для новичков XXL-Job, я по умолчанию вы используете XXl-job.По крайней мере, имейте определенное понимание, если вы хотите начать работу, сначала перейдите к следующим официальным документам

Диаграмма архитектуры

На приведенном выше рисунке представлена ​​общая схема архитектуры версии 2.1, исходный код которой мы хотим проанализировать. Он разделен на две части: центр планирования и исполнитель. Сначала мы анализируем центр планирования, который представляет собой код пакета xxl-job-admin.

основной процесс

XXL-JOB основан на SpringBoot, поэтому наш первый шаг, конечно же, запустить Spring-приложение XxlJobAdminApplication, а затем в нем есть конфигурационный класс XxlJobAdminConfig, который реализует InitializingBean, Spring загрузит этот bean-компонент после инициализации, как показано ниже.

Затем давайте взглянем на метод xxlJobScheduler.init();, как показано ниже.

  • Первый шаг – интернационализация.
  • Второй шаг – отслеживание корреляции.
  • Третий шаг терпит неудачу, и повторная попытка связана.
  • Четвертый шаг — запуск службы на стороне администратора и получение запросов на регистрацию.
  • Планировщик пятого шага JobScheduleHelper, бесконечный цикл, получение задач для выполнения в таблице xxl_job_info, обновление следующего времени выполнения, вызов класса JobTriggerPoolHelper для отправки запланированных задач исполнителю

На самом деле, вышеперечисленные шаги по-прежнему много мест, которые нам нужно понять один за другим, но мы выберем некоторые из них, чтобы изучить сегодня, давайте посмотрим непосредственно на последний шаг JobScheduleHelper

JobScheduleHelper

Очень важный класс, давайте взглянем на его метод start().

На самом деле это очень просто, то есть запускаются два фоновых потока, эти два потока находятся в бесконечном цикле, но эти два потока действительно очень важны. Давайте посмотрим один за другим

Скопировал код напрямую, а дальше давай потихоньку поговорим

  • Код в бесконечном цикле показан на рисунке выше.Сначала оператор for update используется для получения квалификационной блокировки задачи, а затем получается задача, которая будет выполняться в течение следующих 5 секунд.

На самом деле такой код — это наше дело. Кто не приходит сюда с закрытыми глазами, ха-ха, возвращается List of JobInfo, а что, если мы напишем код? Во-первых, конечно, определить, пуст ли он, а затем выполнить обход для обработки каждого объекта, не говоря уже о том, что xxl-job тоже похож на это, а затем выполнить другую обработку бизнес-логики в соответствии с различными атрибутами в объекте, ха-ха, Как вы думаете, фреймворк с открытым исходным кодом и код, который мы обычно пишем, похожи.

Далее берем разные ветки в соответствии с полем triggerNextTime.Всего веток 3. Давайте посмотрим на логику этих веток.

  • Время срабатывания текущей задачи первой ветви истекло более чем на 5 секунд, и оно не выполняется, а непосредственно рассчитывается время следующего срабатывания.
  • Вторая ветвь заключается в том, что время триггера было соблюдено, и класс JobTriggerPoolHelper используется для планирования задачи, а затем оценивается, что если следующее время выполнения находится в пределах 5 секунд, данные задачи кэшируются, а логика обработки то же, что третья ветвь.
  • Давайте посмотрим на это pushTimeRing(ringSecond, jobInfo.getId());
    private void pushTimeRing(int ringSecond, int jobId){
        // push async ring
        List<Integer> ringItemData = ringData.get(ringSecond);
        if (ringItemData == null) {
            ringItemData = new ArrayList<Integer>();
            ringData.put(ringSecond, ringItemData);
        }
        ringItemData.add(jobId);

        logger.debug(">>>>>>>>>>> xxl-job, schedule push time-ring : " + ringSecond + " = " + Arrays.asList(ringItemData) );
    }

ringData — это коллекция карт с целым числом от 0 до 59 в качестве ключа и коллекция jobId в качестве значения. Логика обработки данных этой коллекции находится в нашем втором потоке демона ringThread.

  • Давайте посмотрим на наш второй поток демона
  // ring thread
        ringThread = new Thread(new Runnable() {
            @Override
            public void run() {

                // align second
                try {
                    TimeUnit.MILLISECONDS.sleep(1000 - System.currentTimeMillis()%1000 );
                } catch (InterruptedException e) {
                    if (!ringThreadToStop) {
                        logger.error(e.getMessage(), e);
                    }
                }

                while (!ringThreadToStop) {

                    try {
                        // second data
                        List<Integer> ringItemData = new ArrayList<>();
                        int nowSecond = Calendar.getInstance().get(Calendar.SECOND);   // 避免处理耗时太长,跨过刻度,向前校验一个刻度;
                        for (int i = 0; i < 2; i++) {
                            List<Integer> tmpData = ringData.remove( (nowSecond+60-i)%60 );
                            if (tmpData != null) {
                                ringItemData.addAll(tmpData);
                            }
                        }

                        // ring trigger
                        logger.debug(">>>>>>>>>>> xxl-job, time-ring beat : " + nowSecond + " = " + Arrays.asList(ringItemData) );
                        if (ringItemData.size() > 0) {
                            // do trigger
                            for (int jobId: ringItemData) {
                                // do trigger
                                JobTriggerPoolHelper.trigger(jobId, TriggerTypeEnum.CRON, -1, null, null, null);
                            }
                            // clear
                            ringItemData.clear();
                        }
                    } catch (Exception e) {
                        if (!ringThreadToStop) {
                            logger.error(">>>>>>>>>>> xxl-job, JobScheduleHelper#ringThread error:{}", e);
                        }
                    }

                    // next second, align second
                    try {
                        TimeUnit.MILLISECONDS.sleep(1000 - System.currentTimeMillis()%1000);
                    } catch (InterruptedException e) {
                        if (!ringThreadToStop) {
                            logger.error(e.getMessage(), e);
                        }
                    }
                }
                logger.info(">>>>>>>>>>> xxl-job, JobScheduleHelper#ringThread stop");
            }
        });
        ringThread.setDaemon(true);
        ringThread.setName("xxl-job, admin JobScheduleHelper#ringThread");
        ringThread.start();

По текущему второму тику и предыдущему тику получается задание колеса времени, а затем, как и выше, для планирования задания используется JobTriggerPoolHelper.

Временная диаграмма

ежедневные комплименты

Хорошо всем, вышеизложенное является полным содержанием этой статьи. Люди, которые могут видеть это здесь, всеталант.

Творить нелегко. Ваша поддержка и признание — самая большая мотивация для моего творчества. Увидимся в следующей статье.

Six Meridians Excalibur | Text [Original] Если в этом блоге есть какие-то ошибки, прошу покритиковать и посоветовать, буду очень признателен!

В этой статье используетсяmdniceнабор текста