The approach above is what is known as DYI dependency injection in the Java world. It's totally valid as DI is just a design pattern. But not very common because it does result in a lot of boiler plate code and it's a bit of a PITA to manually wire things up (not to mention error prone).
In the Java world, frameworks such as Spring provide a lot of DI infrastructure that has evolved to require less and less boiler plate. Combined with modern languages such as Kotlin, there is now a lot less need for stating the obvious than ever before.
Simply having a class with a constructor that takes arguments and a single annotation tells Spring "This is a bean, please construct an instance and pass it to places where it is needed as a dependency. It needs other beans to work as well. The names of those beans are the constructor arguments". If you then define those other beans in the same way, Spring takes care of all the plumbing, new calls to constructors of all the beans it has identified, configuration injection (with different profiles, default values, override mechanisms, etc), bean graph validation (no cycles, everything needs to resolve, etc) and then fires the whole thing up.
With stuff like Spring Boot, there is almost no code involved at all and you get a lot of things self initializing using sane defaults simply because the library is on the class path. I've coached a few frontend engineers dealing with some Spring Boot code. I wouldn't go as far as to say that they like it but they were all able to get productive pretty quickly.
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.