In response to Cedric‘s blog on how he doesn’t get IoC, Keith has a really nice summary on why IoC is useful as a principle and what facilities an IoC container should provide. To me, this is the critical thing: IoC is a useful design principle, regardless of whatever opinions you have about the containers themselves.
To me, it‘s also primarily a component-level principle, not something that makes as much intuitive sense at the class level. It is a technique for managing the coupling of components at their usage point. Using it allows you to reuse components, test them in isolation, and build applications out of them.
If you use this principle throughout your code, you may not even need a container as long as you have some controller or assembly class at the top that can configure your components. You can do that with XML and auto-wiring or a beanshell script or simply code. Or more than one of these! These choices vary in how late the decisions are made (compile-time vs runtime) and in ease of reconfiguration. In my experience, it is not only not useful but even confusing to be able to dynamically configure your application to that extent at run-time. Generally, I find it is better to bind the basic structure of your application relatively statically but defer certain decisions to runtime on an as-needed basis.