OSGi is a dynamic module system for Java. So how does it help?
Effective software modules have the following characteristics:
- Self-contained: Although a module is comprised of smaller
parts, it is the whole module that can be moved around, installed,
or uninstalled as a single unit, not the parts within it.
- Highly cohesive: Each module has a coherent logical function.
- Loosely-coupled: Modules have well-defined boundaries between
them.
Modularized systems that have these characteristics are easier
to maintain and extend.
Object-oriented languages such as Java support
modularization. However, they focus on encapsulation of instance variables.
This helps at the object and class level, but does not support higher
forms of modularity. Java EE
helps a little more by providing application-level isolation of application
modules within an enterprise application.
Patterns such as SOA and Dependency Injection encourage modular
design of large-scale enterprise applications. However, this modularity
requires architectural governance rather than being encouraged or
enforced by the runtime environment.
In the Java platform, data
is encapsulated within a class, classes are scoped within a package,
and packages are collected together in a Java archive
(JAR) file. Java class visibility
options are private, package, protected,
and public. There is no access modifier that allows for
a unit of deployment that is a JAR file rather than a package. Most
JAR files consist of multiple packages, and if the JAR file represents
a cohesive function, there is typically a need for classes in one
package to access classes in another package in the same JAR file.
This need requires public accessibility of that class,
which also makes the class visible to classes in other JAR files.
JAR files provide no visibility control. Even well-behaved applications
that use only the classes a JAR file provider expects to be used externally
are governed by the Java class
path, because a required class might be available from multiple JAR
files and the class that is loaded is the first available instance
on the global class path.
JAR files cannot scope the visibility of what they contain, and
also cannot declare their own dependencies. Many JAR files have implicit
dependencies on other JAR files, which means these JAR files cannot
be installed or moved around independently. If a JAR file is installed
and its dependencies are missing, the problem is often not visible
until run time.
Java class loading scans
the class path to look inside each JAR file on the class path to locate
the required class. This process has three main limitations:
- Class path ordering determines which instance of a class is loaded,
and therefore which JAR file it is loaded from.
- Only one version of a class is available on the class path, again
determined by the first instance that is found.
- If the dependencies of a class are not resolved, the first indication
of the problem is often a runtime ClassNotFoundException exception.
These class path and JAR file shortcomings are often referred
to as
"JAR hell". Java EE
partly mitigates these problems. Java EE
introduces the enterprise archive (EAR) file, both as the method by
which an enterprise application is delivered, and as a runtime isolation
scope for the modules that are part of that application. Java EE applications have a class loader hierarchy
that is partly shared between the enterprise applications, and partly
isolated between the applications. For example, in an enterprise application
that contains a web application archive (WAR) module, by default,
the individual WAR modules are isolated from each other in the application,
and isolated from anything in a different application.
While the
"JAR hell" problems are reduced by managing different
class paths with different enterprise applications, there are still
limitations when you want to share libraries such as open source frameworks
or utility libraries between applications.
WebSphere® Application Server offers some advanced
options for configuring enterprise applications to access libraries
that are not delivered as part of the EAR file:
- You can install an isolated library and administratively associate
its classloader with one or more installed modules or applications,
or associate the classloader with the server to make it visible to
all application modules.
- You can configure the classloader delegation pattern to help resolve
versioning compatibility problems. For example, you can specify the
class loader delegation mode as parent-last so that an application-supplied
class is loaded in preference to a server-supplied class.
However, these approaches only partially address the modularity
requirements of applications.
The OSGi Framework offers
a better solution.