Dependency Injection != Service Locator
Part of any Dependency Injection (DI) solution is some sort of registry that contains all of the configured objects with their declared dependencies resolved. In Spring this is the ApplicationContext, and in PicoContainer it’s, well, the PicoContainer.
An alternative application configuration pattern is Service Locator, itself a kind of registry with which any object can look up its dependencies. Because both these patterns have a registry object, it is possible to use the Dependency Injection container as a Service Locator, making all objects dependent on the container class (let’s stick with Spring because I know it better), the ApplicationContext. If you’re going to do Dependency Injection, however, it would be better to have objects coupled only to their precise dependencies, rather than passing an instance of the ApplicationContext to an object.
However, there are more arguments against this than just purity of approach. We recently ran into this tendency on Neuromice, which uses Spring for DI. We also use Quartz for job scheduling, and we had been passing an instance of the ApplicationContext to each job through its JobExecutionContext. The problem with this was that, during unit testing, we needed to pass a valid testing version of our entire ApplicationContext to the job. Theoretically, we could have built a special ApplicationContext that contained only those dependencies needed by the job. However, in Spring at least, that usually means lots of little XML configuration files, so it was easier to have just two context options, the real one and the testing one (which contains all of the data access objects working off of HSQLDB instead of Oracle). Because our application has become fairly complex behind the scenes, creating even the testing version of this ApplicationContext takes ten seconds or so, slowing down our unit tests. It is much faster to create a few mock objects and pass them directly to the job during unit testing. More compelling, this also allows simpler configuration of the interaction of the job with these dependencies. Most compelling, at least to me, passing precise mock objects also does a better job of isolating what’s being tested to just the code in the job. Thankfully, we realized that Spring had recently added a QuartzJobBean superclass, which, if you inherit from it, will set bean property dependencies on your job from attributes in the JobExecutionContext or the SchedulerContext. This means that during unit testing, I can pass a null JobExecutionContext to the job, first fulfilling all the dependencies with mock objects via setters. When the application runs normally, these dependencies are resolved using the beans configured in the ApplicationContext. Very nice.
As a postscript, I recently noticed that someone else beat me to this observation.