OSGi
OSGi is a framework for building modular applications in the JVM.
OSGi concepts
Bundles
- A bundle is the unit of modularisation in OSGi. “It is simply a JAR with additional information. This information allows you to control what packages are imported, exported, as well as which ones are private and/or hidden.” (Instant OSGi Starter)
Lifecycle
Bundles have a lifecycle:
- On Install: Installed → Resolved → Starting → Active
- Then on Stop: → Stopping → Resolved
- Then on Uninstall: → Uninstalled
Start level
A bundle’s start level is a number that indicates when a bundle should be started. A bundle is started if: OSGI framework start-level >= bundle start level
When booting, the OSGi framework starts all bundles whose start level is equal to or lower than that of the framework’s active start level. This is done in ascending order; that is, the framework starts all bundles whose start level is n, then n+1, n+2, …, until n is equal to the framework’s active start level.
For example, if the active start level is 2, then first you’ll start all bundles whose start level is 0, then those whose start level is 1, and then finally those whose start level is 2.
– OSGi in Depth by Alexandre de Castro Alves, Chapter 11: Launching OSGi using start levels
- The default start-level of a Fuse container is
100
. This means it will start all bundles where the start level is 100 or less.
Services
Services are a way of publishing objects (beans) to a central registry, so that they can be consumed by bundles.
Use osgi:service
to define/expose a service, e.g.:
<bean id="myHelloService" .../>
<osgi:service ref="myHelloService" interface="xyz.tomd.HelloService"/>
Use osgi:reference
to reference it from another bundle, e.g.:
<osgi:reference id="myHelloService" interface="xyz.tomd.HelloService"/>
Features
- Features are simply a set of OSGi bundles grouped together into a single deployment
- To upgrade a feature in Karaf/Felix, you have to stop and uninstall the feature first. Use
removeurl
and thenaddurl
to add the URL (mvn:...
) to the new version.
Good practices
- Make bundles as restrictive as possible by exporting (via
Export-Package
) only the classes that absolutely must be shared - Avoid the
Require-Bundle
header, as it can cause split packages (where a package may be split across two bundles that export it); favour fragment bundles instead - Avoid
DynamicImport-Package
because it means the class is only searched for when it is needed, rather than at bundle resolution time. Favour using optional packages or other alternatives.