Butterfly DI Container
Butterfly Container - Introduction
Butterfly Container is a dependency injection container like Spring, Pico and Guice. The core functionality of a dependency injection container is to wire objects together. Your application will ask the container for an object, and the container will make sure that all dependencies (config parameters, collaborating objects, texts etc.) is injected into the object before it is returned to your application.
If you are new to dependency injection, here is a tutorial: What is Dependency Injection?
A dependency injection container can do more than object wiring though. When designed correctly, a dependency injection container can serve as a central integration unit for all resources of your application. Rather than having to design integration mechanisms yourself, and decide on configuration formats etc., you can have the dependency injection container do all that for you. You will just get the needed resource injected directly into the objects you obtain from the container.
The dependency injection container as a central integration unit is illustrated below (in SVG):
Butterfly Container was initially developed as a lightweight alternative to Spring. Granted, there was already Pico Container but it has its own rough edges. Later came Guice, but Guice uses annotations to configure the container, and I am no big fan of annotations for that kind of configuration. I have explained why in the text
Though Spring is reasonably straightforward to configure, it is a large framework by now. It takes an effort to know that to include and not to include of its dependencies. In addition its XML configuration files are verbose, tedious to write and not too easy to read.
Simpler, Java-like Configuration
Butterfly Container started out with a simpler XML configuration file format than Springs. This was soon abandoned since it was too inflexible. Instead a Java-like configuration script language was invented, called Butterfly Container Script. As you will see, this script language is a much simpler way to configure a DI container, than the mechanisms used by Spring, Pico and Guice. Here is a simple example:
myBean1 = * com.jenkov.MyBean(); /* simple instantiation*/ myBean2 = * com.jenkov.MyBean(myBean1); /* constructor injection*/ myBean3 = * com.jenkov.MyBean(myBean2) .setExtraBean(myBean1); /* constructor + setter injection */
Doesn't that look at lot more like Java code than Springs XML config files? It is quite easy to decipher the factory definitions. The MyBean class is just an example. It could be any Java class you like.
More Flexible Configuration
Along with the configuration script language came a lot of nice, very flexible features.
How about extending an existing factory definition? Here is how simple that is:
myBean1 = * com.jenkov.MyBean(); /* simple instantiation*/ myBean2 = myBean1.setValue("Some Value"); /* factory extending myBean1 */
Extending existing factory definitions makes it possible to get rid of close to redundant factory definitions.
Or what about allowing a factory to take input parameters? Here is how:
myBean1 = * com.jenkov.MyBean(); /*simple instantiation*/ myBean2 = myBean1.setValue($0); /*inject input parameter */ myBean3 = myBean2("Parameter Value"); /*factory call with parameter*/
Can you do this with Spring, Pico or Guice?
Still the Lightest
The new, more flexible and advanced configuration language did not make Butterfly Container heavier (in fact it simplified the internal design). With a less than 100 kb JAR file Butterfly Container is still the lightest Java dependency injection container around.
Even if Butterfly Container is the lightest Java DI container around, it still supports most, if not all, DI features offered by Spring, Pico and Guice. For instance:
- Constructor Injection
- Method Injection (Static + Instance)
- Factory Injection
- Instance Life Cycle Management
- New / Singleton
- Thread Singletons
- Local, Anonymous Factories
Butterfly Container also has a few unique features:
- Method Chaining on Methods Returning Void
- Adaptation to Custom Factory Interfaces