IOC Containers

In the Java community there’s been a rush of lightweight containers that help to assemble components from different projects into a cohesive application. Underlying these containers is a common pattern to how they perform the wiring, a concept they refer under the very generic name of “Inversion of Control”. In this article I dig into how this pattern works, under the more specific name of “Dependency Injection”, and contrast it with the Service Locator alternative. The choice between them is less important than the principle of separating configuration from use.

A common issue behind most of the lightweight IOC containers is to deal with - how to wire together different elements: how do you fit together this web controller architecture with that database interface backing when they were built by different teams with little knowledge of each other. Several frameworks are branching out to provide a general capability to assemble components from different layers. These are often referred to as lightweight containers. Examples include PicoContainer, and Spring.

Underlying these containers are a number of interesting design principles.

See Providing centralized, runtime configuration using Plugins

The implementation class for the abstraction (Interface) isn’t linked into the program at compile time, since we don’t know which concrete implementation needs to be used. Instead we want the abstraction to work with any implementation, and for that implementation to be plugged in at some later point, out of our hands. The problem is how can we make that link so that the class using the abstraction is ignorant of the implementation class, but can still talk to an instance to do its work.

Expanding this into a real system, we might have dozens of such services and components. In each case we can abstract our use of these components by talking to them through an interface (and using an adapter if the component isn’t designed with an interface in mind). But if we wish to deploy this system in different ways, we need to use plugins to handle the interaction with these services so we can use different implementations in different deployments.

So the core problem is how do we assemble these plugins into an application? This is one of the main problems that this new breed of lightweight containers face, and universally they all do it using Inversion of Control.

Inversion of control is a common characteristic of all (or most) frameworks. The question is: “what aspect of control are they inverting?”

What aspect of control are they inverting?

For this new breed of containers, the inversion is about how they lookup a plugin implementation. The approach that these containers use is to ensure that any user of a plugin follows some convention that allows a separate assembler module to inject the implementation into the class that needs that concrete implementation.

The specific name for this pattern is Dependency Injection.

Dependency Injection is not the only way of removing the dependency from the application class to the plugin implementation. The other pattern you can use to do this is Service Locator.

There are several techniques possible for each of these steps based on the technology/language you are using for your implementation.

We can achieve Inversion of Control through various mechanisms such as:

  1. Strategy design pattern,
  2. Service Locator pattern,
  3. Factory pattern, and
  4. Dependency Injection (DI).

Examples

  1. Spring IOC Container
  2. Contexts and Dependency Injection (CDI) (almost the same thing as Guice, but is a JSR rather than proprietary)
  3. Pico Container: http://picocontainer.com/
  4. Google Guice: https://github.com/google/guice
  5. Dagger: https://dagger.dev/

Tags

  1. Dependency Injection pattern