'dependency injection with OSGI
I have built an application with the dependency framework Guice. Now I will move over to OSGI and started to extend my jars with bundle information.
The main problem, which I currently face is, how to set up the dependency injection correctly. I have bundle A, which exports some packages. Then Bundle B defines a component, which needs some object (class AA) of bundle A injected.
I could set up a service for the class AA in bundle A, which will be injected automatically, but what if bundle A has also a dependency to some class in bundle A, which is maybe not exported. Do I have to set up the second class then also as service, which will not work, because it is not exported.
The following code will show the problem:
Bundle A
package test.bundleA.api
public class AA {
@Inject
public AA(AInternal someReference) {...}
}
package test.bundleA.internal
public class AInternal {...}
Bundle B:
package test.bundleB.api
public class ComponentB {
@Inject
public ComponentB(AA refToA) {...}
}
When I will use any other classes in bundle A from the exported package, do I have then to set up for each of them a service?
What is a common approach to solve the problem of dependency injection inside the bundle and even over bundle boundaries?
Solution 1:[1]
If you are independent of using Guice I would recommend to use Eclipse+Bndtools to create your OSGi bundles. With Bndtools, its quite easy to create OSGi bundles and also DI via Annotations. Let's take an example:
You have an interface in bundleA:
public interface Greeting {
String sayHello(String name);
}
An implementation in bundleB where @Component
enables our bundle to use OSGi Declarative Service.
@Component
public class ExampleComponent implements Greeting {
public String sayHello(String name) {
return "Hello " + name;
}
}
And in the end a third bundleC where you want to us DI and inject all Greeting
implementation to a specific component for usage.
@Component
public class GreetingCommand {
private Greeting greetingSvc;
@Reference
public void setGreeting(Greeting greetingSvc) {
this.greetingSvc = greetingSvc;
}
public void greet(String name) {
System.out.println(greetingSvc.sayHello(name));
}
}
As you can see with @Reference
you indicate that you want to inject an implementation of your Greeting
interface. The example above uses OSGi Declarative Services in combination with Bndtools. Bndtools itself takes the annotations and creates a XML file needed for OSGi to use Declarative Services. I don't want to go more deep into it. Please see [1] and [2] for more information. Just wanted to show you how DI is made by using declarative services and Bndtools.
Solution 2:[2]
Well, there is a extension library called Peaberry which provide integration Guice with OSGi. There is nice example how to inject a service bundle into another bundle.
Hope you will find it helpful.
Solution 3:[3]
The solution to your specific scenario is to define a public factory (builder) service/component that you can register with osgi and inject that type. The factory impl can be defined in the same module, and create the internal type via a 'create' or 'build' method with a return type of a public interface type, but the impl is internal.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | christian.vogel |
Solution 2 | Milan Baran |
Solution 3 | Eric Aya |