OSGi és classloderek

May 29, 2014,

Ha alapokról kellene elkezdeni az OSGi működését – mondjuk egy tanfolyam keretében – akkor biztos, hogy még mielőtt bármit elmondanánk, a classloaderek működését kéne megértetni. Igazából meglehetősen egyszerűek a szabályok, de jó tudatosítani őket. Ha nem ismerjük a szabályokat, az OSGi konténerünk változatos ClassNotFound exception-ök dzsungelévé tud válni. De ha tudjuk mi hogy működik, elég egyszerű rátalálni az ösvényre.

Kérdés: Milyen classloader fogja betölteni az osztályunkat, ha eddig még nem volt betöltve, de a kódunkban valahol szerepel a new MyClass() kifejezés.

Válasz: Az a classloader, aki azt a kódot töltötte be, ahol példányosítani próbálunk.

1. Példa

Tegyük fel, hogy van 2 bundle-unk a konténerben (legyen mondjuk a nevük service és client).

A service tartalma:

A client tartalma:

Ebben eddig semmi meglepő nincs. Tudjuk, hogy az OSGi bundle egy sima jar file, ami attól érzi magasabb rendűnek magát, hogy a MANIFEST-ben okos mondásokat tartalmaz. A service például megengedi, hogy a hu.dpc.demo.osgi.util csomag alatt található osztályokat bárki lássa, aki szeretné.. Az igényt az Import-Package mondással jelenti be a client bundle.

Két class loaderünk lesz tehát, mindegyik bundle-nak egy. Ha a clientben valami nem található, a service classloadere is az exportált packagekből adhat osztályokat. Ha a BundleActivator-ban (ami esetünkben kb. olyan mint a main) meghívjuk a new FactoryUtil() konstruktor, akkor mivel a saját classloader nem tölti be, az import nyomán megtalált service classloader ad nekünk egy FactoryUtilt. A new Account()-ot viszont egyértelműen a service classloadere hozza létre, hiszen a FactoryUtil-t – akiben ez a a példányosítás szerepelt – is ő hozta létre.

2. példa

Miért fontos ez? Próbáljunk elképzelni egy olyan felállást, amikor a service szeretne plugint betölteni futás közben. Például:

A service tartalma:

A client tartalma:

Mi fog történni? A FactoryUtil-t a service bundle töltötte be. A client bundle látja az exportált dolgokat a service-ből, de a service semmit se tud a clientről. Tehát a plugin leírót se fogja megtalálni és null-al fog visszatérni a getPluginRegistration("myPlugin") hívás.

Természetesen még rengeteg lehetőségünk van. Egyrészt vannak további OSGi trükkök Dynamic import, Fragment Bundle, másrészt level3-on már belép az, amikor kézzel állítgatjuk különböző framework-ök classloadereit. (Általában a jól megtervezett frameworkök azt vagy engedik vagy kifejezetten igénylik…). De ezek részletes kifejtése sajnos nem fér ide a margóra. Frameworkök tervezéséhez viszont ezt a remek bejegyzést ajánljuk.

Discussion