środa, 7 marca 2012

EIwS-Cert - współbieżność w Springu (cz. 3)

Oprócz programowego podejścia do uruchamiania i planowania wykonania zadań Spring w ramach konfiguracji xml'owej udostępnia specjalną przestrzeń wspierającą współbieżność: xmlns:task="http://www.springframework.org/schema/task" dostępnej pod adresem: xsi:schemaLocation="http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd".

Dzięki konfiguracji można zdefiniować executor'a, scheduler'a czy opisać zadania, które mają zostać zrealizowane z wykorzystaniem konkretnego mechanizmu. Przyjrzyjmy się zatem konkretnym przykładom.

Definiowanie executor'a
Rzućmy najpierw okiem na przykład:

<task:executor id="executor" pool-size="1-10" queue-capacity="200" keep-alive="60" rejection-policy="DISCARD_OLDEST"/>
Powyższa definicja jest tak naprawdę odpowiednikiem definicji springowego bean'a będącego ThreadPoolTaskEecutor'em o identyfikatorze executor (identyfikator ten będzie prefixem dla nazw wątków przypisanych do tego executor'a), mającego określoną core'ową (1) i maksymalną (10) liczbę wątków, pojemność kolejki - 200, a czas życia wątku bez przydzielonego zadania 60 sekund, dodatkowo w przypadku przekroczenia wielkości kolejki i sytuacji w której wszystkie wątki pracują obowiązuje polityka wycofywania najstarszego zadania.

Definiowanie scheduler'a
Przykład:

<task:scheduler id="schedulerId" pool-size="10" />
Tak jak w przypadku executor'a, który jest bean'em ThreadPoolTaskExecutor, tak w tym wypadku powyższa definicja jest równoważna definicji bean'a ThreadPoolTaskScheduler o identyfikatorze "schedulerId" i przypisanej liczbie wątków równej 10.

Definiowanie zadań do wykonania
Skoro w łatwy sposób w ramach xml'owej konfiguracji można utworzyć mechanizmy współbieżności czy da się również zdefiniować w łatwy sposób to co ma być wykonane? Okazuje się, że tak: wystarczy skorzystać z scheduled-tasks.

Załóżmy, że mamy zdefiniowany scheduler - tak jak przedstawiono powyżej oraz dodatkowo bean'a springowego o identyfikatorze: businessId, który udostępnia jedną, bezparametrową metodę processWork. Chcielibyśmy, aby ta metoda odpalana była np. co 5 sekund od poprzedniego uruchomienia. Dzięki xml'owej konfiguracji powyższe wymagania można zrealizować za pomocą poniższego kodu:

<task:scheduled-tasks scheduler="schedulerId">
    <task:scheduled ref="businessId" method="processWork" fixed-rate="5000"/>
</task:scheduled-tasks>
Element task:scheduled pozwala wskazać na bean'a (atrybut ref) oraz na metodę tego bean'a (atrybut method), która ma być cyklicznie uruchamiana. Dodatkowo możliwe jest określenie cyklu uruchamiania zadania (za pomocą fixed-rate, fixed-delay, wyrażenia cron lub własnej implementacji interfejsu Trigger'a.)

W ramach pojedynczej definicji scheduled-tasks można określić wiele zadań wykonywanych przez ten sam scheduler.

Adnotacje i współbieżność
Nie da się obecnie nie zauważyć, że coraz częściej zamiast konfiguracji xml'owej preferowane są adnotacje. W tym zakresie Spring wychodzi naprzeciw oczekiwaniom i dostarcza dwie adnotacje, pierwsza pozwala oznaczyć metodę jako wykonywalną asynchronicznie: Async. Natomiast druga - Scheduled, oznacza, że dana metoda ma być wykonywana cyklicznie.
  • Scheduled  - pozwala za pomocą 3 wykluczających się wzajemnie parametrów określić cykliczność uruchamiania danej metody (cron, fixedDelay lub fixedRate). Metoda, której adnotacja jest przypisywana musi być metodą bezparametrową zwracającą void'a.
  • Async - metoda, której zostanie przypisana adnotacja Async może przyjmować wiele parametrów natomiast nie może zwracać niczego poza void'em lub Future'em. W momencie wywołania rejestrowane jest zadanie do wykonania, natomiast sterowanie natychmiast zwracane jest do wywołującego wątku. Adnotacji tej nie można łączyć z adnotacjami zarządzającymi cyklem życia bean'a springowego.
Poniżej przykłady:

   1:  @Scheduled(cron="* * * * * *")
   2:  public void scheduleWork() {
   3:      // some work...
   4:  }
Metoda scheduleWork() będzie wywoływana co 1 sekundę

   1:  @Async
   2:  public Future<Integer> processWork(int i) {
   3:      // some work...
   4:      return new AsyncResult<Integer>(10);
   5:  }
Wywołania powyższej metody będą wykonywane asynchronicznie. Metoda przyjmuje jeden parametr i w odpowiedzi po przeliczeniu danych zwraca wartość całkowitą, która dostępna będzie w wątku wywołującym po przetworzeniu zlecenia przez wątek z puli realizujących zadania asynchroniczne.

Z dobrodziejstwa adnotacji można skorzystać po odpowiednim skonfigurowaniu kontenera. W konfiguracji XML'owej należy dodać:

<task:annotation-driven executor="executorBean" scheduler="schedulerBean"/>
W ten sposób definiuje się, że wszelkie wywołania metod z adnotacjami Async będą wykonywana przez executora: executorBean, natomiast wszystkie cykliczne zadania (metody z adnotacjami Scheduled) będą realizowane przez scheduler: schedulerBean.

Myślę, że tym akcentem można zamknąć temat współbieżności w Springu i w Javie. Kolejny temat, który zamierzam opisać w ramach przygotowań do zdobycia certyfikatu to wywołania zdalne.

Brak komentarzy:

Prześlij komentarz