Планиране в Джакарта EE

1. Общ преглед

В предишна статия демонстрирахме как да планирате задачи през пролетта с помощта@Планирананотация. В тази статия ще покажем как да постигнем същото, като използваме услугата за таймер в приложение за Джакарта EE за всеки случай, представен в предишната статия.

2. Активирайте поддръжка за планиране

В приложение за Джакарта EE не е необходимо да се активира поддръжка за задания по време. Услугата за таймер е услуга, управлявана от контейнер, която позволява на приложенията да извикват методи, които са планирани за събития, базирани на времето. Като пример може да се наложи приложението да изготвя някои ежедневни отчети в определен час, за да генерира статистика.

Има два вида таймери:

  • Програмни таймери : услугата за таймер може да се инжектира във всеки компонент (с изключение на сеанс със състояние) и бизнес логиката трябва да бъде поставена в метод, анотиран с @Timeout . Таймерът може да бъде инициализиран от метод, анотиран @PostConstruct на зърната, или може да бъде инициализиран само чрез извикване на метод.
  • Автоматични таймери : бизнес логиката се поставя във всеки метод, коментиран с @Schedule или @Schedules . Тези таймери се инициализират веднага след стартирането на приложението.

Така че нека да започнем с нашия първи пример.

3. Планирайте задачата с фиксирано закъснение

През пролетта това се прави просто с помощта на @Scheduled (fixedDelay = 1000) анотация. В този случай продължителността между края на последното изпълнение и началото на следващото изпълнение е фиксирана. Задачата винаги чака, докато предишната приключи.

Правенето на същото нещо в Джакарта EE е малко по-трудно за постигане, тъй като не е осигурен подобен вграден механизъм, въпреки това подобен сценарий може да се приложи с малко допълнително кодиране. Нека да разгледаме как се прави това:

@Singleton public class FixedTimerBean { @EJB private WorkerBean workerBean; @Lock(LockType.READ) @Schedule(second = "*/5", minute = "*", hour = "*", persistent = false) public void atSchedule() throws InterruptedException { workerBean.doTimerWork(); } } 
@Singleton public class WorkerBean { private AtomicBoolean busy = new AtomicBoolean(false); @Lock(LockType.READ) public void doTimerWork() throws InterruptedException { if (!busy.compareAndSet(false, true)) { return; } try { Thread.sleep(20000L); } finally { busy.set(false); } } }

Както можете да видите таймерът е планиран да се задейства на всеки пет секунди. Обаче методът, задействан в нашия случай, симулира 20 секунди време за отговор чрез повикване sleep () на текущата нишка .

В резултат на това контейнерът ще продължи да извиква doTimerWork () на всеки пет секунди, но условието, поставено в началото на метода, busy.compareAndSet (false, true), ще се върне незабавно, ако предишното повикване не е приключило. В това ние гарантираме, че следващата задача ще бъде изпълнена само след като приключи предишната.

4. Планирайте задачата с фиксирана ставка

Един от начините да направите това е да използвате услугата за таймер, която се инжектира с помощта на @Resource и конфигурира в метода, анотиран @PostConstruct . Методът, коментиран с @Timeout, ще бъде извикан, когато таймерът изтече.

Както бе споменато в предишната статия, началото на изпълнението на задачата не чака завършването на предишното изпълнение. Тази опция трябва да се използва, когато всяко изпълнение на задачата е независимо. Следният кодов фрагмент създава таймер, който се задейства всяка секунда:

@Startup @Singleton public class ProgrammaticAtFixedRateTimerBean { @Inject Event event; @Resource TimerService timerService; @PostConstruct public void initialize() { timerService.createTimer(0,1000, "Every second timer with no delay"); } @Timeout public void programmaticTimout(Timer timer) { event.fire(new TimerEvent(timer.getInfo().toString())); } }

Друг начин е да се използва @Scheduled анотация. В следния кодов фрагмент задействаме таймер на всеки пет секунди:

@Startup @Singleton public class ScheduleTimerBean { @Inject Event event; @Schedule(hour = "*", minute = "*", second = "*/5", info = "Every 5 seconds timer") public void automaticallyScheduled(Timer timer) { fireEvent(timer); } private void fireEvent(Timer timer) { event.fire(new TimerEvent(timer.getInfo().toString())); } }

5. Планирайте задачата с първоначално закъснение

Ако вашият сценарий на употреба изисква таймерът да започне със закъснение, можем да направим и това. В този случай Джакарта EE позволява използването на услугата за таймер. Нека да разгледаме пример, при който таймерът има първоначално закъснение от 10 секунди и след това се задейства на всеки пет секунди:

@Startup @Singleton public class ProgrammaticWithInitialFixedDelayTimerBean { @Inject Event event; @Resource TimerService timerService; @PostConstruct public void initialize() { timerService.createTimer(10000, 5000, "Delay 10 seconds then every 5 seconds timer"); } @Timeout public void programmaticTimout(Timer timer) { event.fire(new TimerEvent(timer.getInfo().toString())); } }

Методът createTimer , използван в нашата извадка, използва следния подпис c reateTimer (дълго начална продължителност, дълъг интервалДурация, java.io.Serializable информация), където началната продължителност е броят на милисекундите, които трябва да изтекат преди известието за изтичане на първия таймер, а intervalDuration е броят на милисекунди, които трябва да изминат между известията за изтичане на таймера.

В този пример използваме начална продължителност от 10 секунди и интервал от пет секунди. Задачата ще бъде изпълнена за първи път след стойността за начална продължителност и ще продължи да се изпълнява в съответствие с intervalDuration .

6. Планирайте задачата с помощта на Cron Expressions

Всички планиращи програми, които сме виждали, както програмни, така и автоматични, позволяват използването на cron изрази. Да видим пример:

@Schedules ({ @Schedule(dayOfMonth="Last"), @Schedule(dayOfWeek="Fri", hour="23") }) public void doPeriodicCleanup() { ... }

В този пример методът doPeriodicCleanup () ще бъде извикан всеки петък в 23:00 и в последния ден от месеца.

7. Заключение

В тази статия разгледахме различни начини за планиране на задачи в околната среда на Джакарта EE, като използвахме като отправна точка предишна статия, където пробите бяха направени с помощта на Spring.

Примери за кодове могат да бъдат намерени в хранилището на GitHub.