При создании любого приложения критически важно знать, для какого часового пояса мы его создаем. Если приложение предназначено для того же региона, где оно разрабатывается, не беда. Однако ситуация становится критической, когда приложение должно быть развернуто в других регионах!

У меня недавно был такой сценарий. Хотя вариант использования является распространенным, он немного сложен. В этом блоге я постараюсь помочь разработчикам, столкнувшимся с подобными ситуациями. Просто замечание: может быть больше способов решить эту проблему. Я показываю только то, с чем ездил.

Итак, вот мой вариант использования:

Мы создаем его с использованием среды Spring Boot для создания веб-приложения. Разработчик сидит в Пакистане и превращает кофе в код. Однако приложение предназначено для развертывания в ближневосточном регионе.

Теперь нам нужно написать планировщик, который подбирает транзакции в полночь. Затем проделайте с ним какое-нибудь волшебство. И, наконец, обновляет записи в базе данных.

Проблема: Разработчик находится в Пакистане, а код должен выполняться на Ближнем Востоке? Мы на час опережаем регион MENA, так что чья полночь. Вот где часовые пояса помогают нам в Java.

Поскольку я не могу поделиться проприетарным кодом, я собираюсь создать новое приложение Spring Boot, используя Spring 3.0. Если вы используете более старую версию Spring, вы все равно можете запустить код. Здесь я предполагаю, что вы уже знаете, как работают фреймворки Spring.

Файл application.properties

Файл application.properties — это то, как Spring управляет конфигурациями. Здесь мы добавляем новую строку, как показано ниже:

# Time zone for the region where the application is to be executed
timezone=Asia/Karachi

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

Добавление часового пояса в планировщике

Представьте, что у меня есть планировщик. Затем я могу ввести часовой пояс, используя выражение Spring ${property-name}.

package com.example.springschedulars.springscheduler.scheduler;

import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;

@Configuration
@EnableScheduling
public class MidNightScheduler {

    // Scheduled to be executed at the midnight
    // The timezone comes from the application.properties
    // Depending upon the region, timezone can be changed as desired
    @Scheduled(cron="0 0 0 * * *", zone="${timezone}") 
    public void runSchedule() {
        
        /*
         * Some code here that mimics actual application logic
         * 
         */

        System.out.println("Scheduled job running");

    }

}

Приведенный выше код прост. Во-первых, мы включаем планирование, вызывая метод Spring EnableScheduling. Затем мы присваиваем выражению cron значение 0 0 0 * * *, что означает: 0-я секунда 0-й минуты 0-го часа каждого месяца каждый день!

Теперь предположим, что если бы мы разрабатывали его локально в Пакистане, мы могли бы изменить часовой пояс региона в файле application-properties на Asia/Karachi. Теперь, когда нам нужно развернуть приложение, скажем, в Дубае, мы можем установить в поле значение: Asia/Dubai.

Единственная проблема здесь будет заключаться в следующем: если наше приложение необходимо развернуть в нескольких регионах, нам потребуются либо отдельные свойства приложения, либо отдельные процессы CI/CD.

Вход в планировщик

Итак, выше мы могли решить проблему с часовым поясом. Ради полноты и того, что я гик, я добавлю еще одну часть. То есть использовать Aориентированное Oпрограммирование O в Spring для регистрации выполнения расписания.

Во-первых, мне нужно создать файл aspect. Я создам новый package с именем aspects. Внутри этого пакета я создам свои файлы pointcut, aspect и jointpoint.

Ниже приведены эти три файла:

package com.example.springschedulers.springscheduler.aspects;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LogScheduler {

}
package com.example.springschedulers.springscheduler.aspects;

import org.aspectj.lang.annotation.Pointcut;

public class CommonPointCuts {

    @Pointcut("@annotation(com.example.springschedulers.springscheduler.aspects.LogScheduler)")
    public void logSchedulersPointCut() {
    }
}

Наконец, мой aspect как:

package com.example.springschedulers.springscheduler.aspects;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.context.annotation.Configuration;

@Aspect
@Configuration
public class LoggingAspect {

    /*
     * This method is executed when the scheduler is to be executed. 
     * It will log the scheduler about to be executed.
     */
    @Before("com.example.springschedulers.springscheduler.aspects.CommonPointCuts.logSchedulersPointCut()")
    public void logMethodCallBeforeExecution(JoinPoint joinPoint) {

        String className = joinPoint.getSignature().getDeclaringTypeName();
        String methodName = joinPoint.getSignature().getName();

        StringBuilder sb = new StringBuilder(className);
        sb.append(".");
        sb.append(methodName);
        
        System.out.println("Starting scheduler: " + sb.toString());

    }
}

Теперь, когда наш аспект готов, пора добавить его к нашему schedulers. Для моего случая я создам два планировщика: MidNightScheduler и EveryHourScheduler.

package com.example.springschedulers.springscheduler.scheduler;

import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;

import com.example.springschedulers.springscheduler.aspects.LogScheduler;

@Configuration
@EnableScheduling
public class MidNightScheduler {

    // Scheduled to be executed at the midnight
    // The timezone comes from the application.properties
    // Depending upon the region, timezone can be changed as desired
    // @Scheduled(cron="0 0 0 * * *", zone="${timezone}") 
    @Scheduled(fixedDelay = 5000)
    @LogScheduler
    public void runSchedule() {
        
        /*
         * Some code here that mimics actual application logic
         * 
         */
        System.out.println("Scheduled job running");
    }
}
package com.example.springschedulers.springscheduler.scheduler;

import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;

import com.example.springschedulers.springscheduler.aspects.LogScheduler;


@Configuration
@EnableScheduling
public class EveryHourScheduler {

    // Calling the scheduler to log the execution
    @LogScheduler
    // Scheduled to be executed at the midnight
    // The timezone comes from the application.properties
    // Depending upon the region, timezone can be changed as desired
    @Scheduled(cron="0 0 * * * *", zone="${timezone}") 
    public void runSchedule() {
        
        /*
         * Some code here that mimics actual application logic
         * 
         */
        System.out.println("Scheduled job running");
    }
}

Теперь, когда наши планировщики запустятся, ниже будет вывод:

Starting scheduler: com.example.springschedulers.springscheduler.scheduler.MidNightScheduler.runSchedule
Starting scheduler: com.example.springschedulers.springscheduler.scheduler.EveryHourScheduler.runSchedule

Вы можете найти полный код по адресу: umairk83/spring-schedulars (github.com)

Спасибо, что прочитали эту статью. Вы можете найти меня по адресу: Умаир Хан | ЛинкедИн. Если вам нужна какая-либо статья, свяжитесь со мной по адресу: Umair K. — технический писатель — фрилансер Upwork из Карачи, Пакистан и https://www.fiverr.com/umairk83