I am now researching on the Opendaylight project (an open-source SDN controller project leaded by Cisco), and discovered that the project uses resources from apache.felix.dm package to dynamically manage the service dependencies on equinox (an OSGi framework) during runtime.
To understand the mechanism of dm, I have traced the code in ComponentImpl.java under apache.felix.dm package. What I understand now is:
The invoking mechanism written in code is provided as follow (they are both located in ComponentImpl.java):
The method to invoke init():
private void activateService(State state) {
String init;
synchronized (this) {
init = m_callbackInit;
}
// service activation logic, first we initialize the service instance itself
// meaning it is created if necessary and the bundle context is set
initService();
// now is the time to configure the service, meaning all required
// dependencies will be set and any callbacks called
configureService(state);
// flag that our instance has been created
m_isInstantiated = true;
// then we invoke the init callback so the service can further initialize
// itself
invoke(init);
// see if any of this caused further state changes
calculateStateChanges();
}
The method to invoke start():
private void bindService(State state) {
String start;
synchronized (this) {
start = m_callbackStart;
}
// configure service with extra-dependencies which might have been added from init() method.
configureServiceWithExtraDependencies(state);
// inform the state listeners we're starting
stateListenersStarting();
// invoke the start callback, since we're now ready to be used
invoke(start);
// start tracking optional services
startTrackingOptional(state);
// register the service in the framework's service registry
registerService();
// inform the state listeners we've started
stateListenersStarted();
}
Now my question is: what's the difference between init() and start() method? Since they are both invoked before the service being registered on OSGi framework, why they needed to be seperated? Thx for any ideas, and please tell me if any of my understanding is incorrect.
Best Regards,
Jay
The reason for having both an init
and start
method is as follows. The dependency manager allows you to declaratively define components and their dependencies in (Java) code. This can be done when you start the bundle, but sometimes a component might have a dependency that depends on some configuration, or one of its other dependencies. In other words, you might have dependencies that you want to add to the component at runtime.
In such cases, what you can do is define an init(Component c)
method on your component implementation. This method will be invoked after your component has been initialized and all its required dependencies have been injected (or their callbacks invoked). So at that point you have access to such dependencies in your component and you could decide, based on information obtained through such dependencies, to dynamically add yet another component, like this:
public volatile OtherService s; // an injected service dependency
public void init(Component c) {
if (s.needsSomeService()) {
DependencyManager dm = c.getDependencyManager();
c.add(dm.createServiceDependency()
.setService(SomeService.class)
.setInstanceBound(true)
.setRequired(true));
}
}
Once SomeService
becomes available, the start()
method will be invoked and your component becomes available (meaning if it publishes a service, that will be done now).
In short: the init
method exists to allow you to manipulate your own component definition and add extra dependencies dynamically at runtime. The start
method is then invoked once all dependencies are available.
In simple scenarios, where you have no such requirements, using either method to do your initialization is fine.