In a previous article I’ve defined a component/container architecture and explained the reasons why such architecture is used. This article will cover real examples of containers which are known to me. in historical perspective.
Earliest containers known to me are servlet containers. These are typical IoC containers, used on servers communicating asymmetric request/response protocols, like HTTP. This allows applying IoC approach to handling of protocol logic: servlets must implement “Servlet” interface containing method “service()”. This method is invoked by container for each incoming request. For HTTP, IoC principle also applies to creation and sending of responses.
Interface “Servlet” also contains methods “init()” and “destroy()”, which are used for lifecycle management. Method “init()” also used for “context” injection. From this “context” a servlet can extract references to all components it depends on.
Servlets are developed according to special convention, so they are collections of classes and XML descriptor.
Well-known examples of servlet containers are Apache Tomcat, Jetty, Resin.
EJB spec is also quite old. It is a “generic” component/container architecture for complex data-processing logic used inn enterprize IT systems. Curioulsy enough, it was developed as distributed architecture, meaning that each component will be located on dedicated machine, and container will provide inter-component communication. IoC principle is applied to lifecycle and persistence. Dependencies are resolved using lookup (in JNDI facility), however binding in JNDI is done automatically.
Later EJB spec changed to support “local” access between components. Anyway, it was and still criticised for being complex and slow, and many other frameworks emerged to fix its flaws.
Well-known examples of EJB containers are: Glassfish, Apache OpenEJB, JBoss, JOnAs, Bea WebLogic, IBM websphere, and lots of others.
Microcontainers are “generic” component containers focusing only on local access and providing just lifecycle and late binding. All other features could be realized “on top” of container, by implementing them as a components.
Apache Avalon was first known to me attempt to build “lightweight” container. Later its developers divided, but they have tried to support common framework for containers. This framework follows “interface injection” approach, which means that dependency on something is declared by implementing certain interface, and the same interface is used for injecting this dependency. Thus, Avalon framework contains lots of interfaces, for example for lifecycle, logging, configuration. However, injection is used only for dependencies which are part of framework. For resolving other dependencies there is also lookup facility.
Apache Hivemind is another minimalistic container, with IoC principles applied to lifecycle, configuration and automatic dependency injection, although lookup is also supported. This container is best classified as “declarative de-centralized”. It uses a special format for its components (code + XML-based descriptor). Dependency injection is supported through components following a naming convention.
Other examples of microcontainers are: Picocontainer, Butterfly, Guice.
Spring framework is a set of components aimed to be simple, lightweight and cheap alternatives to all parts of JEE. As a a replacement of EJB it provides a much simpler IoC container. However, this container is often used not just for binding user components together, but also for binding them with system components. This was new at the time, because JEE application servers didn’t allow to customize the “system” part. Spring container is not just “business logic integration point”, but whole “application integration point”.
IoC principle in Spring could be applied to lots of concerns, including lifecycle, dependency resolving via injection, configuration. However, usage of IoC is not mandatory and could be avoided, but it will make whole arcitecture less consistent.
One interesting application of IoC principle used Spring is “aspect-oriented programming”: a container “wraps” modules with its own “proxy”, and injects this proxy into dependent modules. This “proxy” allows inserting some functionality before invocation and after invocation, so some component can affect interaction between two other modules without modifying them.
Spring is very popular, because it provides a large base for building custom server-side software, either complex or simple.
JEE application servers
After success of Spring vendors of many JEE application servers understood that their products should be more customizable, so those servers were re-designed as microcontainers. Apache Geronimo is a microcontainer allows deployment of components called “GBeans”. JBoss also implements microcontainer architecture. Glassfish and JOnAs stated that they will move to OSGi.
Apache Geronimo is an example of “embedded container” architecture: EJB container (OpenEJB) is itself a component in another container (Geronimo microcontainer).
The distinguishing feature of OSGi framework is a complex classloading. This allows “hot upgrade” through dynamic loading and unloading of classes, and other interesting capabilities. IoC principle is applied only to lifecycle. As a separate component there is a “service facility” which could be used for basic dependency lookup, and also allows subscription to notifications about lifecycle events in other services. There is also component for dependency injection called “Service Binder” based on XML descriptors.
There are several implementations of OSGi framework, including Eclipse Equinox and Apache Felix.
JSLEE is another non-generic component architecture for Java. It is similar to EJB in a way in which IoC principle is applied to persistence and lifecycle. JSLEE includes scalable event-delivery facility, and IoC principle is appled to some aspects of interfaction between components and event-delivery facility. could be viewed as a combination of Servlet Container and EJB container. Dependencies are resolved using lookup (in JNDI).