sixlegs.com / blog / java / not-a-container.html

Root Beer Logo Root Beer

Chris Nokleberg's Fizzy Weblog

July 2003
Su M Tu W Th F Sa
    1 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
Previous  |  Next  |  More...
#  Not-A-Container

Well, even if it didn't get many comments, my last blog entry did help to clarify my own thinking on what a service framework should be. I've continued to read the picocontainer-dev archives and all related blogs, and one great idea I heard was to use dynamic proxies for services to enable hot-swapping. Not being stricken with IoC tunnel-vision lets me take this to the logical conclusion, and so I present the Not-A-Container, AKA "Type-4 IoC" [Emoticon]

Assume a service interface with two implementations:

public interface Speaker {
    void saySomething();
}

public class HelloSpeaker implements Speaker {
    public void saySomething() {
        System.out.println("Hello!");
    }
}

public class GoodbyeSpeaker implements Speaker {
    public void saySomething() {
        System.out.println("Goodbye!");
    }
}

Now let's go as far away from IoC as possible--a static final pointer to a specific instance of the service. We'll put it in an interface so that any class can implement it to inherit the constant:

public interface MyServices {
    public static final Speaker SPEAKER = /* revealed later */
}

Using the service from any class is simple, just reference it as MyServices.SPEAKER, or implement the interface and drop the prefix:

public class MyComponent implements MyServices {
    public void run() {
        SPEAKER.saySomething();
    }
}

I think it would be hard to argue that this isn't the simplest a service framework could get, as least as far as the component writer is concerned. But how to make it work? Well, the MyServices class actually looks like:

public interface MyServices {
    public static final Speaker SPEAKER =
      (Speaker)NotAContainer.get(Speaker.class);
}

NotAContainer returns an object that implements the Speaker interface but can be dynamically bound (and re-bound) to an actual Speaker implementation at any time.

In the following test program, the Speaker service is first bound to HelloSpeaker and then to GoodbyeSpeaker. Note that while the API is static, ThreadLocals are used so that the binding is per-thread.

public class Main {
    public static void main(String[] args) {
        MyComponent c = new MyComponent();

        NotAContainer.set(Speaker.class, new HelloSpeaker());
        c.run();

        NotAContainer.set(Speaker.class, new GoodbyeSpeaker());
        c.run();
    }
}

To make this entry a little shorter I've omitted the code for NotAContainer, but it is only 33 lines long. Click here to download a zip of all the source files. I wrote it using CGLIB, so you'll have to download that too, although reimplementing using dynamic proxies should be trivial.

[Powered By FreeMarker]  [Valid Atom 1.0]  [Weblog Commenting by HaloScan.com]