Java Reference
In-Depth Information
be loaded from the application server classes. This may not seem like a big problem,
but Java EE contains an awful lot of containers and frameworks that provide hook and
plug points to application code. In order to load these classes, the frameworks, which
are part of the base application server runtime, have to have access to the application.
This problem is bypassed in enterprise Java using the concept of the thread context
classloader . This classloader has visibility to the classes inside the application module
and is attached to the thread whenever a managed object (like a servlet or EJB ) is exe-
cuting. This classloader can then be retrieved and used by the framework code to
access classes and resources in the application module that called into it. This solution
works, but it means that many useful frameworks rely heavily on the thread context
classloader being set appropriately. In OSG i, the thread context classloader is rarely
set, and furthermore it completely violates the modularity of your system. There's no
guarantee that classes loaded by the thread context classloader will match your class
space; in particular, there's no assurance that you'll share a common view of the inter-
face that needs to be implemented. This causes a big problem for Java EE technolo-
gies in OSG i.
META-INF SERVICES AND THE FACTORY PATTERN
Although reflection, dynamic classloading, and the thread context classloader are use-
ful, they're of limited practical use in writing loosely coupled systems. For example,
reflection doesn't allow an implementation of an interface to be discovered, unless
the implementation's class name is already known. Having to specify implementation
names in advance pretty much defeats the point of using interfaces. This problem
crops up again and again in Java EE and, unsurprisingly, there's a common pattern for
solving it.
For many years, the best solution to the problem of obtaining interface implemen-
tations was to isolate the problem to one area of code, known as a factory . The system
wasn't loosely coupled, but at least only one area was tightly coupled. The factory
would use reflection to instantiate a class whose name had been hardcoded into the
factory. This didn't do much to eliminate the logical dependency between the factory
and the implementation, but at least the compile-time dependency went away.
A better pattern was to externalize the implementation's class name out to a file on
disk or in a JAR , which was then read in by the factory. The implementation still had to
be specified, but at least it could be changed without recompiling the factory. This
pattern was formalized into what's known as META-INF services. Any JAR can register
an implementation for any interface by providing the implementation name in a file
named after the interface it implements, found in the META-INF /services folder of the
JAR . Factories can look up interface implementations using a ServiceLoader and all
registered implementations will be returned.
This mechanism sounds similar to OSG i services. Why isn't this good enough for
OSG i? One practical reason is that the service registry for META-INF services wasn't avail-
able when OSG i was being put together. The other, more relevant issues are that,
although META-INF services avoids tight coupling in code, it doesn't give any dynamism
Search WWH ::




Custom Search