I think what you are referring to is just manually doing DI. I.e. you defined constructors that accept dependencies and then call them all in a main function. I think this is tolerable if your codebase is structured for it. In typical java codebases, it gets ugly really fast. IMO this is caused by a general proliferation in the number of classes (due to class-per-file among other reasons), as well as a tendency to never use "static" DI. As an extreme example, if you needed to inject a logging dependency, then almost all code would need to be part of the DI graph. In a typical web backend, you might DI the sql connection pool. This causes basically all code to need DI since it either uses sql or has a transitive dependency that uses sql. IMO injecting the connection pool is not useful since it's not useful to write tests where you inject anything other than a real sql connection.