Spring DI promotes loosely coupled code because the Spring container injects your dependencies based on configuration. If you are implementing interface implementations, you do not need to change the code to change which particular implementation will be introduced unless you consider your configuration code, which many do.
If you use Factory to create customized objects that are used by the rest of your code, you write code to create objects, configure them, etc. If you want to change what Factory returns, you must change the actual code, which, according to some, will be a more intrusive change.
Typically, Spring is used to customize how the various layers of your application connect together. For example, service X accepts such and such DAO implementations. This organization is an application tier. Suppose you have a script in which you want to create a button for each line in the list β in this case, you could use Factory to create the buttons. This scenario is based on a run-time situation when the GUI has different elements that you could not configure in advance (because they are data-based), so the DI here is of less importance.
EDIT - based on your comments, I think the main point here is that you have to consider that Spring is also an Inversion of Control container. This means that you are not programming which components in your application go there. Without IoC, you can do something like
MyServiceImpl extends MyService { Dao1 = new Dao1Impl(); // you programmatically configure which components go in here Dao2 = new Dao2Impl(); .... }
instead, you do something like
MyServiceImpl extends MyService { public Dao1;
In the second code example, Spring (or whatever you use) will introduce the appropriate DAO instances to you. You have taken control of which components will be used at a higher level. Thus, IoC and DI go hand in hand, IoC helps to loosen the connection, because in your component definitions (for example, interfaces) you specify only behavior.
In other words, IoC and DI are not needed for loose communication; You can have a free connection with Factory too
MyServiceImpl extends MyService { public dao1 public dao2; MyServiceImpl(){ dao1 = DaoFactory.getDao1(); ... } .... }
here, your service still depends only on the DAO definitions, and you use Factory to get the implementations. The caveat is that your service is now associated with a factory. You can make it freer by passing Factory to your constructor if you want ....
Also, keep in mind that Spring provides other useful features, such as transaction management. This is incredibly useful, although you said that you do not need this for your application.