What's the difference between OSGI bundles and components?
getting started with osgi, i wonder what's the conceptual diffence between bundles and c开发者_运维知识库omponents. And when to use which of them. Any pointers are welcome.
EDIT:
Components and Bundles provide different interfaces and therefore they are probably not interchangeable
ComponentContext
BundleContext
A component is:
- an active participant in the system
- aware of and adapt to its environment
- environment = services provided by other components
- environment = resources, devices, ...
- may provide services to other components and use services from other components
- have a lifecycle
In short:
- Component provide services
- Bundle manage the lifecycle
A bundle can have only one activator (needing a BundleContext
), and can have as many active components as you want.
That means you may end up trying to fit in one activator several loosely-related concerns into a single class.
That is why it may be easier to manage those components by Declarative Services, through the SCR (the "Service Component Runtime" which is an "extender bundle" implementing the new and improved OSGi R4.2 DS - Declarative Service - specification).
This is especially true since OSGi 4.2 because it is now much easier to write DS components as POJOs: the activate
and deactivate
methods are no longer required to take a ComponentContext
parameter. See also Lazy Declarative Service.
Note:
It can help to replace those terms in the context of OSGi and look at "how we got there" (excellent blog post by Neil Bartlett)
Here are some relevant extracts, where the "modules" end up being the OSGi Bundles (managing Components which declare Services):
Module Separation
Our first requirement is to cleanly separate modules so that classes from one module do not have the uncontrolled ability to see and obscure classes from other modules.
In traditional Java the so-called “classpath” is an enormous list of classes, and if multiple classes happen to have the same fully-qualified name then the first will always be found and the second and all others will be ignored.The way to prevent uncontrolled visibility and obscuring of classes is to create a class loader for each module. A class loader is able to load only the classes it knows about directly, which in our system would be the contents of a single module.
Module Access level
If we stop here then modules will be completely isolated and unable to communicate with each other. To make the system practical we need to add back in the ability to see classes in other modules, but we do it in a careful and constrained way.
At this point we input another requirement: modules would like the ability to hide some of their implementation details.We would like to have a “module” access level, but the problem today is that the javac compiler has no idea where the module boundaries lie.
The solution we choose in our module system is to allow modules to “export” only portions of their contents. If some part of a module is non-exported then it simply cannot be seen by other modules.
When importing, we should import what we actually need to use, irrespective of where it comes from and ignoring all the things that happen to be packaged alongside it.
Granularity of Exports and Imports
OSGi chooses packages.
The contents of a Java package are intended to be somewhat coherent, but it is not too onerous to list packages as imports and exports, and it doesn’t break anything to put some packages in one module and other packages in another module.
Code that is supposed to be internal to our module can be placed in one or more non-exported packages.
Package Wiring
Now that we have a model for how modules isolate themselves and then reconnect, we can imagine building a framework that constructs concrete runtime instances of these modules. It would be responsible for installing modules and constructing class loaders that know about the contents of their respective modules.
Then it would look at the imports of newly installed modules and trying to find matching exports.
An unexpected benefit from this is we can dynamically install, update and uninstall modules. Installing a new module has no effect on those modules that are already resolved, though it may enable some previously unresolvable modules to be resolved. When uninstalling or updating, the framework knows exactly which modules are affected and it will change their state if necessary.
Versions
Our module system is looking good, but we cannot yet handle the changes that inevitably occur in modules over time. We need to support versions.
How do we do this? First, an exporter can simply state some useful information about the packages it is exporting: “this is version 1.0.0 of the API”. An importer can now import only the version that is compatible with what it expects and has been compiled/tested against, and refuse to accept
Packaging Modules and Metadata
Our module system will need a way to package the contents of a module along with metadata describing the imports and exports into a deployable unit.
So the only question is, where should we put the metadata, i.e. the lists of imports and exports, versions and so on?
As it happens OSGi was designed before 2000, so it did choose either of these solutions. Instead it looked back at the JAR File Specification, where the answer is spelled out:
META-INF/MANIFEST.MF
is the standard location for arbitrary application-specific metadata.
Late Binding
The final piece of modularity puzzle is late binding of implementations to interfaces. I would argue that it is a crucial feature of modularity, even though some module systems ignore it entirely, or at least consider it out of scope.
We should look for a decentralised approach.
Rather than being told what to do by the God Class, let us suppose that each module can simply create objects and publish them somewhere that the other modules can find them. We call these published objects “services”, and the place where they are published the “service registry”.
The most important information about a service is the interface (or interfaces) that it implements, so we can use that as the primary registration key.
Now a module needing to find instances of a particular interface can simply query the registry and find out what services are available at that time. The registry itself is still a central component existing outside of any module, but it is not “God”… rather, it is like a shared whiteboard.
In OSGi terminology a "component" is like a run-time service. Each component has an implementation class, and can optionally implement a public interface, effectively providing this "service". This aspect of OSGi is sometimes likened to a service registry pattern.
Components in OSGi are, by definition, provided by a bundle. A bundle may contain/provide multiple components. While by itself a bundle may not provide a service, components/declarative services are used to make OSGi more service oriented. You are under no obligation to use components/services.
精彩评论