The dependency injection in pure Java is a really simple concept. Suppose you have a classes A and B as follows:
public class A{
    private B instanceOfB = new B();
    public method doSomething(){
        // does something involving B
    }
}
Class A internally instantiates class B and so B becomes A's dependency. If you want to test A in isolation, you cannot do it (because it depends on B). If you want to provide A with a different implementation of B, you have to edit the source code of A, which is not always possible or just not the best idea.
Instead consider injecting a dependency through constructor (it is one of the methods you can choose with Spring). You create a public constructor for A, which takes a B as an argument:
class A{
    private B instanceOfB;
    public A(B instanceOfB){
        this.instanceOfB = instanceOfB;
    }
    public method doSomething(){
        // does something involving B
    }
}
Now, instead of constructing the object inside class, you give it (inject) a parameter in an outside code. The advantage of this is that you can pass a different implementation of B, or a mock for testing:
class B{ // whatever }
class B2 extends B{ // whatever }
A anInstanceOfA = new A(new B()); // this is ok, A will internally use B
A anotherInstanceOfA = new A(new B2()); // and this instance will use B2 instead
If B and B2 implement the same interface or B2 extends B, you can use them interchangeably depending on your needs. This provides a great deal of flexibility. This is basically how dependency injection without a DI container works. Spring might be an overkill for small applications, but the basic idea is really simple, it is a good practice and you should definitely use it.
A good resource to learn basics about Spring (and other things) is Java Brains.