Zrozum pojęcia OSGi. Spróbuj podążać za łamigłówką
Opublikowany: 2013-04-20OSGi
stało się dziś bardzo popularne dzięki swojemu modułowemu podejściu i możliwości narzucania logicznych granic między modułami. Kiedy odkrywamy to po raz pierwszy, pojawia się pytanie, od czego zacząć rozumieć, jak to działa?
Aby zrozumieć koncepcje OSGi, postaramy się zastosować podejście zagadkowe, chodzi o rozpoczęcie od trywialnej części tej technologii i poszukiwanie innych części powiązanych z tymi znalezionymi. W ułożeniu puzzli pomoże nam JArchitect, który będzie pomocny w wykrywaniu wewnętrznego projektu OSGi.
Aby być bardziej konkretnym, analizujemy za pomocą JArchitect aplikację korzystającą z technologii OSGi, dotyczy ona słynnego środowiska eclipse IDE, które wykorzystuje równonoc kontenera OSGi.
Zacznijmy od typowej definicji OSGi:
OSGi zmniejsza złożoność, zapewniając modułową architekturę dzisiejszym wielkoskalowym systemom rozproszonym, a także małym aplikacjom wbudowanym. Budowanie systemów z własnych i gotowych modułów znacznie zmniejsza złożoność, a tym samym koszty rozwoju i utrzymania. Model programowania OSGi realizuje obietnicę systemów opartych na komponentach.
Trywialną częścią OSGi jest modułowość, zobaczmy, czym są moduły OSGi?
Moduły OSGI nazywane są Bundles i dlatego każda aplikacja składa się z przynajmniej jednego pakietu.
Te pakiety są wykonywane wewnątrz kontenera, a ponieważ każde podejście modułowe, w którym kontener zarządza modułami, pytanie brzmi, która umowa musi implementować każdy moduł, aby był zintegrowany z kontenerem?
Weźmy jako przykład pakiet org.eclipse.equinox.jsp.jasper i wyszukajmy wszystkie jego zaimplementowane interfejsy, w tym celu możemy wykonać następujące żądanie CQLinq:
1 2 3 4 |
from t in Types where t . ParentProject . Name ==” org . eclipse . equinox . jsp . jasper_1 . 0.300.v20110502 “ let interfaces = t . InterfacesImplemented from i in interfaces select i |
Zaimplementowano interfejs BundleActivator z pakietu OSGi, który zawiera dwie metody start i stop, przydatne do dostosowania uruchamiania i zatrzymywania pakietu.
Inną specyfiką pakietu jest jego plik manifestu, oto część z pliku manifestu org.eclipse.equinox.jsp.jasper:
1 2 3 4 5 6 7 8 9 |
Manifest - Version : 1.0 Bundle - Localization : plugin Bundle - RequiredExecutionEnvironment : CDC - 1.0 / Foundation - 1.0 , J2SE - 1.3 Bundle - SymbolicName : org . eclipse . equinox . jsp . jasper Eclipse - LazyStart : true Eclipse - SourceReferences : scm : cvs : pserver : dev . eclipse . org : / cvsroot / rt : org . eclipse . equinox / server - side / bundles / org . eclipse . equinox . jsp . jaspe r ; tag = v20110502 Bundle - Activator : org . eclipse . equinox . internal . jsp . jasper . Activator |
Jak widać, ten manifest zawiera pewne metainformacje potrzebne kontenerowi, takie jak określenie klasy aktywatora pakietu, która implementuje interfejs BundleActivator.
Paczka reprezentuje nasz pierwszy element układanki, a oto uproszczona reprezentacja paczki:
Aby mieć pojęcie o wszystkich pakietach używanych przez eclipse, poszukajmy wszystkich klas implementujących interfejs BundleActivator.
1 2 |
from t in Types where t . Implement ( “ org . osgi . framework . BundleActivator “ ) select new { t , t . NbBCInstructions } |
Kto zarządza pakietem i może wywoływać metody BundleActivator?
Aby to odkryć, poszukajmy metod wywołujących bezpośrednio lub pośrednio BundleActivator.start
1 2 3 4 |
from m in Methods let depth0 = m . DepthOfIsUsing ( “ org . eclipse . osgi . framework . internal . core . BundleContextImpl . startActivator ( BundleActivator ) “ ) where depth0 > = 0 orderby depth0 select new { m , depth0 } |
Pakiet jest aktywowany przez framework OSGi w momencie jego uruchomienia. Klasa frameworka jest uruchamiana przez kontener równonocy. Aby lepiej zrozumieć, co się dzieje po uruchomieniu kontenera, oto kilka akcji wykonywanych po uruchomieniu kontenera:
Po uruchomieniu kontenera inicjuje on framework OSGi, framework pobiera wszystkie zainstalowane pakiety i dla każdego z nich tworzy instancję klasy BundleHost i przechowuje znaleziony pakiet w repozytorium.
Klasa BundleHost implementuje interfejs Bundle, który zawiera metody takie jak start, stop, odinstalowywanie i aktualizacja, metody te są potrzebne do zarządzania cyklem życia pakietu.
Więc naszym drugim elementem układanki jest kontener OSGi, uruchamiany przez Equinoxlauncher, który inicjuje framework. Klasa framework odpowiada za ładowanie paczek i ich aktywację.
Po odkryciu podstawowych pojęć dotyczących pakietu i kontenera zajrzyjmy głęboko do pakietów i odkryjmy, jak działają wewnętrznie.
Weźmy jako przykład pakiet org.eclipse.equinox.http.servlet i poszukajmy metod wywoływanych przez metodę start jej klasy Activator.
Ten pakiet tworzy usługę i rejestruje ją w kontenerze. Usługa w OSGi jest zdefiniowana przez standardową klasę lub interfejs Java. Zazwyczaj interfejs Java jest używany do definiowania interfejsu usługi. Usługa jest preferowaną metodą, której pakiety powinny używać do komunikowania się między sobą.

Oto kilka przydatnych scenariuszy korzystania z usług:
- Eksportuj funkcjonalność z pakietu do innych pakietów.
- Importuj funkcjonalność z innych pakietów.
- Zarejestruj detektory wydarzeń z innych pakietów.
Kolejną uwagą z poprzedniego wykresu zależności jest to, że do utworzenia wystąpienia usługi używana jest fabryka usług.
Naszym trzecim elementem układanki jest warstwa usług OSGi, każdy pakiet może używać lub deklarować jakieś usługi, co wymusza podejście do projektowania komponentów, oto nowa reprezentacja pakietu OSGi.
Jeśli pakiet używa usług do komunikacji z innymi pakietami, w jaki sposób komunikuje się z innymi plikami JAR?
Jeśli opracujemy pakiet i spróbujemy użyć klasy z innego jara, możemy się zdziwić, że nie zadziała zgodnie z oczekiwaniami, powodem jest to, że ClassLoader jest podpięty przez kontener OSGi, aby sprawdzić, czy przeszukajmy, która metoda wywołuje java. lang.Thread.setContextClassLoader.
1 2 |
from m in Methods where m . IsUsing ( “ java . lang . Thread . setContextClassLoader ( ClassLoader ) “ ) select new { m , m . NbBCInstructions } |
Wywołuje go wiele metod, w tym EquinoxLauncher. więc za każdym razem, gdy paczka próbuje utworzyć instancję klasy, kontener OSGi sprawdzi, czy kod może wykonać tę akcję, czy nie, i tutaj pojawia się rola importowanego i eksportowanego pakietu w pliku manifestu.
1 2 3 4 |
Export - Package : org . eclipse . equinox . http . servlet ; version =” 1.1.0 ″ Import - Package : javax . servlet ; version =” 2.3 ″ , javax . servlet . http ; version =” 2.3 ″ , org . osgi . framework ; version =” 1.3.0 ″ , org . osgi . service . http ; versi on =” [ 1.2 , 1.3 ) ” |
Pakiet deklaruje jawnie wyeksportowany i zaimportowany pakiet. Aby to sprawdzić, wyszukajmy pakiety używane przez pakiet org.eclipse.equinox.http.servlet i sprawdź, czy używa on tylko pakietu importowanego.
1 2 |
from n in Packages where n . IsUsedBy ( “ org . eclipse . equinox . http . servlet_1 . 1.200.v20110502 “ ) select new { n , n . NbBCInstructions } |
Jak widać, wszystkie użyte pakiety są wyszczególnione w pliku manifestu, w sekcji importu pakietów.
Wyeksportowany pakiet reprezentuje jednak pakiet, którego można użyć z innych pakietów. jest reprezentowany przez interfejs ExportedPackage i możemy wyszukiwać klasy kontenerów za pomocą tego interfejsu.
1 2 |
from t in Types where t . IsUsing ( “ org . osgi . service . packageadmin . ExportedPackage “ ) select new { t , t . NbBCInstructions } |
Interesujące w przypadku tej nowej możliwości jest to, że pakiet będzie miał dobrze zdefiniowaną granicę, a to, czego używa i co udostępnia jako usługi, jest bardzo dobrze określone.
Sprawdzenie wykorzystania importowanych pakietów możemy wymusić za pomocą innych narzędzi, np. za pomocą CQLinq możemy napisać pewne reguły ostrzegające za każdym razem, gdy projekt używa innych pakietów niż określone, ale lepiej mieć taką kontrolę w środowisku wykonawczym, więc deweloper nie może łamać tych zasad.
Ta zdolność do przetwarzania importowanych i eksportowanych pakietów jest zarządzana przez warstwę modułów OSGi i był to nasz czwarty element układanki.
Wróćmy do kontenera OSGi i zobaczmy, jakie usługi świadczy?
Usługi kontenerowe
Jak odkryliśmy przed uruchomieniem kontenera przez klasę EquinoxLauncher, a klasa frameworka inicjuje i uruchamia pakiety, aby wykryć, które usługi są dostarczane, przeszukajmy wszystkie klasy użyte w metodzie inicjalizacji frameworka.
1 2 |
from t in Types where t . IsUsedBy ( “ org . eclipse . osgi . framework . internal . core . Framework . initialize ( FrameworkAdaptor ) “ ) select new { t , t . NbBCInstructions } |
Niektóre klasy zostały już wcześniej odkryte, takie jak BundleRepository, BundleHost,PackageAdminImpl i ServiceRegistry.
A co z innymi klasami:
- StartLevelManager:
Każdy pakiet OSGi jest powiązany z poziomem uruchamiania, który umożliwia serwerowi kontrolowanie względnej kolejności uruchamiania i zatrzymywania pakietów. Tylko pakiety, których poziom początkowy jest mniejszy lub równy aktywnemu poziomowi początkowemu struktury serwera, muszą być aktywne. Zazwyczaj pakiet o niższym poziomie początkowym zaczyna się wcześniej. - Administrator zabezpieczeń:
Warstwa bezpieczeństwa obsługuje aspekty bezpieczeństwa, ograniczając funkcjonalność pakietu do wstępnie zdefiniowanych możliwości. - Menedżer zdarzeń:
Usługa Administrowanie zdarzeniami udostępnia model publikowania-subskrypcji do obsługi zdarzeń. Jest ona realizowana zgodnie ze Specyfikacją usług administratora zdarzeń OSGi. Usługa Administrowanie zdarzeniami wysyła zdarzenia między wydawcami zdarzeń a subskrybentami zdarzeń (obsługi obsługi zdarzeń) przez wprowadzenie kanału zdarzeń. Wydawcy publikują zdarzenia w kanale, a kanał zdarzeń określa, które programy obsługi muszą zostać powiadomione. W związku z tym wydawcy i osoby zajmujące się obsługą nie mają o sobie bezpośredniej wiedzy, co upraszcza zarządzanie zdarzeniami.
Cały obraz OSGi
Złóżmy wszystkie opisane wcześniej elementy układanki, a otrzymamy następujący obrazek OSGi:
Ta architektura ma następujące interesujące zalety:
- Prosty.
- Zmniejszona złożoność.
- Łatwe wdrażanie.
- Bezpieczne.
Co sprawia, że jest to bardzo atrakcyjne i warte objazdu, a nie będziesz tracić czasu, jeśli przestudiujesz go dogłębnie.