Click here to Skip to main content
15,895,011 members
Articles / Programming Languages / Java
Tip/Trick

Simple IoC Container Base on ConcurrentHashMap

Rate me:
Please Sign up or sign in to vote.
3.50/5 (2 votes)
23 Jan 2015CPOL3 min read 14.1K   5
Is it easy to create an IoC container?

Introduction

Do you need an IoC container in your Java project? Are you familiar with XML hell of Spring IoC or is Google Guice flexible enough? Why don't you create your own IoC container with special requirement for your project?

I usually create some experiment code, it's too small to use Spring IoC with some XML file and Guice doesn't allow to modify container at runtime (there are some trick to do this but more code is needed and maybe don't support type check). I am also not familiar with annotation. So I decided to create my own tiny container. If you also want to create your own container, my article maybe helpful for you.

Background

Forget all complexity of DI and IoC definition, a simple IoC container can consider as a Map<Class,Object>. You can make an association between a Class and an Object, and you need a function with input parameter as Class and return according Object. Map can satisfy those requirements, but in multi-thread scene traditional Map has poor performance (the reason can be explained by another long article). So I chose ConcurrentHashMap designed by Doug Lea.

It's better if a container also supports type check.

Declare ConcurrentHashMap as Container

It's quite easy and simple like this:

Java
private ConcurrentHashMap<Class<?>, 
Object> container = new ConcurrentHashMap<Class<?>, Object>();

We will store Class and Object as a pair.

Register or Create Binding between Class and Object

Java
public <K, V extends K> boolean regit(Class<K> key, V value) {
    return container.put(key, value) == null;
}

The magic of Type check comes from:

Java
<K, V extends K>

This declares 2 classes: K and V inheritant K. If you put an object of class that doesn't extends K, Java compiler will raise an exception (In Eclipse IDE, you will not compile project).

Get Object Binding with Class

Java
public <K, V extends K> V resolve(Class<K> keyObject) {

    return (V) container.get(keyObject);
}

Because we checked type when we create binding, we don't have to check it again when we retrieve object.

More Features with regit(Class,Class)

I think regit(Class,Object) can solve most cases, but it's useful if we provide automatic creating object feature .

Java
public <K, V extends K> boolean regit(Class<K> key, Class<V> value)
        throws Exception {
    V object;
    try {
        object = ReflectHelper.createObject(this,value);
    } catch (Exception e) {
        throw e;
    }
    return (container.put(key, object) == null);
}

How can we create programmatic objects?

Java
public static <V> V createObject
(ITypeCheckContainer container, Class<V> v) throws Exception{
    V result = null;
    Constructor[] constructors = v.getConstructors();
    Constructor willBeImplemented = constructors[0];
    for(int i = 1; i <constructors.length; i++){
        if(willBeImplemented.getParameterCount() >
            constructors[i].getParameterCount()) willBeImplemented = constructors[i];
    }
    Parameter[] para = willBeImplemented.getParameters();
    Object[] objectPara = new Object[para.length];
    for(int i = 0;i < para.length;i++){
        Class<?> clazz = para[i].getType();
        objectPara[i] = container.resolve(clazz);
        if(objectPara[i] == null) return null;
    }
    try {
        result = (V) willBeImplemented.newInstance(objectPara);
    } catch (InstantiationException | IllegalAccessException
            | IllegalArgumentException | InvocationTargetException e) {

        throw e;
    }
    return result;
}

Package java.lang.reflect.* contains a lot of information about Class. We can do a lot of things with this package, programmatic creating object is just a small example.

Usage

Create a class or an interface name Father, and 2 other class Child1, Child2 inherited from Father. You can easy regit and get instance like this:

Java
//Regit
ITypeCheckContainer container = new ConcurrentHashMapContainer();
container.regit(Father.class, new Child1());
container.regit(Child2.class, new Child2());
//Resolve
container.resolve(Child1.class);
container.resolve(Child2.class).doSomething();

Performance Compare

 

I reuse and modify test scenario from this article http://java.dzone.com/articles/java-7-hashmap-vs (thanks to Pierre-Hugues Charbonneau for this useful article).

At one glance, I created some concurrent threads to get object from each container (number of threads is from 1 to 50), each scenario runs 5 times and I use average data for comparing. Details of results can be found at my Github repository.

Image 1

You can see FastIoC spend less time than Guice. On an average, FastIoC spends 0.001544 seconds, Guice spends 0.00264 seconds.

Conclusion

This tiny IoC container may be useful for small and experiment projects. Its code also demonstrates how to work with Generic of Java also about java.lang.reflect package.

Welcome any suggestion for improving source code, I will appreciate all comments. Please update the latest source code from my Github repository at https://github.com/vudangngoc/FastIoC.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Technical Lead Orchestra Networks
Vietnam Vietnam
Java programmer at Orchestra Networks

Comments and Discussions

 
SuggestionOptimizations Pin
Chad3F26-Jan-15 14:33
Chad3F26-Jan-15 14:33 
GeneralRe: Optimizations Pin
vudangngoc26-Jan-15 16:03
vudangngoc26-Jan-15 16:03 
Question[My vote of 2] Good for exercise, imo not good advice for actual use Pin
mrcellux23-Jan-15 7:09
mrcellux23-Jan-15 7:09 
Why do you think eg Guice is not flexible enough? To me it looks more flexible for this use case alone, its also just few lines of code at max to initialize for a simple project.

"for lazy coders don't want to create object by themself" -
I've worked on a project having custom DI container where devs weren't lazy to instantiate and it was a maintenance hell. Think about constructor changes, circular dependencies, order of construction, transitive dependencies.

By the time this solution becomes truly viable it will be no less simple than the other ioc containers you mention.

In any case it's a great exercise to play with something like this, gives you insight how such containers work under the hood. Some devs consider it magic without looking further. For the same reason you should definitely look into annotations and understand their great usefulness in this area. It's the weapon of choice for the popular containers for a good reason.
AnswerRe: [My vote of 2] Good for exercise, imo not good advice for actual use Pin
vudangngoc23-Jan-15 9:09
vudangngoc23-Jan-15 9:09 
GeneralRe: [My vote of 2] Good for exercise, imo not good advice for actual use Pin
mrcellux23-Jan-15 9:58
mrcellux23-Jan-15 9:58 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.