In short (perhaps I should write an article), global configuration is handled by a singleton, or thread-local. During bootstrapping the desired implementations are created and their interfaces stored in the configuration. Modules that need certain interfaces refer to the global configurator (or ConfigurationManager, or ComponentFactory, or however you'd like to call it) and request the component they want. Often the components will be lazily created, rather than during bootstrapping.
This allows the same ability as dependency injection of mocking interfaces for tests, and having good control over what objects are created. It saves on the overhead of passing around components through the layers.
Ah, that's neat. I believe I've seen a hybrid approach of sorts used in some .NET apps.
A good example of this is Flask. At one point I was using Flask-HTTPAuth and I ran into some issues. I made a suggestion to the maintainer that maybe we could pass certain things into functions via dependency injection (using python decorators). He ended up not going ahead with my suggestion, partly because that's not really how Flask works - the idiom is to use a thread-local "global" object to set and retrieve such information, as @mortoray
points out. I did make a small pull request to clean up the code that was accepted though! :) I do tend to prefer the dependency injection concept in general, though one has to be careful with that too. It can be quite easy to create a very complicated configuration where it becomes hard to understand how things are getting set up.
We're a place where coders share, stay up-to-date and grow their careers.
We strive for transparency and don't collect excess data.