First, dependency injection is not java specific. This is a misconception. It's a good idea in lots of other languages. Separating glue code from business logic (which is what dependency injection is) is a good idea no matter what you use and a specific instance of separation of concerns. That's never a bad idea. You should do that in every language that you use. How you do this works different for different languages.
Second: DIY Dependency Injection is easy: it's a design pattern, not a framework. Though of course there are several good Java frameworks for this of course that you probably want to use. Writing glue code manually is monkey work. Automating that is a good idea.
The way this works is simply applying a few rules:
- Code modules/classes/objects/functions, etc. that contain business logic don't create anything that they need (aka dependencies) themselves. Instead everything they need is given to them via parameters (aka. injecting). In Java the best place to do this would be the constructor. Setter injection is also a thing but constructor injection is what you should be doing.
- Code that builds/constructs/initializes/configures like constructors, main methods, beforeTest methods etc. should not do work other than that: don't put business logic here. This is where glue code goes. Glue code should never mix with business logic.
That's it. Simple. Create stuff, inject it where it is needed. Do that consistently. If you find you need to inject a lot of stuff in one place, that's a coupling and cohesiveness problem: fix it because your design is broken.
There's nothing Java specific here. It's a logical consequence of applying SOLID principles. You cannot do that and NOT be doing dependency injection. You can do this in Javascript, Ruby, python, Haskell, lisp, etc. Every time you hear about code being hard to test or maintain, you'll find that people were mixing glue code and logic and made a big mess. Every one of those languages has good idioms for doing this.