Dependency Injection (or DI for short) is a method of Inversion of Control — a method to help reduce class dependencies. In the case of Dependency Injection, it removes the need for the class itself to acquire/find it's dependency [often having been made a global or singleton, or gotten from one, not having seen alternatives], instead leaving this responsibility up to it's owner. This has a number of advantages.
The basic concept
The basic concept, then, is that instead of having the class "ask" how to get whatever it depends on, it is instead "told" ("injected") to/into it.
The advantages of Dependency Injection
Flexibility
By telling the object in question exactly what you want it to depend on, it's extremely easy to customize the number and combination of objects. Server processes can easily be told to use separate logs or share, and dummy testing harness objects easily hoisted into place for higher code coverage unit tests without littering the original source with branches and conditionals.
Simplicity
Implementation and use can't get any simpler.
Examples
Advanced Injectors
So far, we've only talked about per-resource injectors. With a lot of dependencies, this can get big — and repetitive — very fast. Fortunately, we're not limited to such setups. On the simple end of automation, you could build simple structures to pass a set of related resources together with. On the more advanced side of things, you could have an entire scripting or configuration file system managing possible wiring combinations and managing shared resource lifetimes layered atop more basic systems (consider how you might implement an Apache clone, for example, with it's various logging levels, combinations, and log generators).