Skip to content
This repository has been archived by the owner on Aug 31, 2019. It is now read-only.
sameb edited this page Jul 7, 2014 · 1 revision

Using Guice in an OSGi container

OSGi

OSGi is a dynamic module system used in many projects including Eclipse and GlassFish. A module in OSGi is known as a bundle - basically a JAR with additional metadata. This metadata describes the bundle's identity, what packages it needs, and what it provides. Guice added OSGi metadata in its second release, which means you can now install it as a bundle on any modern OSGi container.

OSGi containers also provide a shared service registry, which supports dynamic collaboration between bundles by letting them publish and consume services on-the-fly in the same JVM. Guice can integrate with the OSGi service registry via the third-party peaberry extension.

Can I use Guice in an OSGi environment without peaberry? Short answer: yes!

Long answer: Guice is a valid OSGi bundle which contains code to transparently support AOP inside OSGi containers. You can share module bindings and injectors between your OSGi bundles and use method interception on public methods, without needing the peaberry extension.

What are the benefits of peaberry?

peaberry exposes a fluent API to publish and consume dynamic services. It provides integration with the OSGi service registry out of the box and has plug-in support for other registry-based service frameworks. Think of peaberry as the equivalent of Spring Dynamic-Modules, but with the type-safety and performance of Guice, and the ability to work with other service frameworks - not just OSGi.

With peaberry you can inject OSGi services just like any other Guice binding. The bindings remain valid and transparently continue to work as services are updated. You can inject Export handles that let you publish and unpublish instances (or bound types) as OSGi services. You can even use a form of outjection to watch for changes in injected services.

Last, but definitely not least, peaberry brings OSGi service support to your existing Guice application without introducing any OSGi specific types. You can switch between a fixed Java instance or an OSGi service for the same injection point just by changing your binding modules.

What are the constraints of using Guice's OSGi support?

Guice uses bytecode generation for AOP, faster reflection, and to proxy circular dependencies. The generated bytecode must be able to see both the original client type (available from the client classloader) and AOP internals (available from the Guice classloader), but in OSGi these classloaders will be isolated from one another. The client classloader will only see its own types and imports, while Guice will only see its own types and imports.

To support AOP in OSGi without requiring clients to know about AOP internals, or vice-versa, Guice automatically creates and manages bridge classloaders that bridge between client and Guice classloaders. The bridge classloaders also support eager unloading of proxy classes, which reduces the potential for memory leaks when reloading bundles.

This is only possible when the types involved are not package-private (because by definition package-private types are not visible from other classloaders). If you attempt to use AOP on package-private types while running inside an OSGi container you will see the following exception:

 ClassNotFoundException: com.google.inject.internal.cglib.core.ReflectUtils

because bridging wasn't possible. If you need to use AOP with package-private types or methods in OSGi then you can always put Guice and the AOP Alliance JAR on the main classpath and use the org.osgi.framework.bootdelegation property to expose the Guice packages, like so:

 "-Dorg.osgi.framework.bootdelegation=org.aopalliance.*,com.google.inject.*"

You can still dynamically unload and reload bundles when using bootdelegation with Guice, but you would need to restart the JVM to replace the Guice bundle itself. This is much less likely to happen compared to upgrading client bundles, and it's usually fine to do a full shutdown when a key production service is upgraded. This also avoids potential problems like serialization-compatibility for HTTP session objects.

Clone this wiki locally