4

Introduction and Question

I understand what the advantages of dependency injection, e.g. constructor injection or setter injection and that it is one way of doing inversion of control. I also understand that service locators are another way of doing inversion of control - but one that should be avoided. I am following the terminology of Martin Fowler.

Dependency injection as a principle can easily done by simply defining an interface having (possibly multiple) implementations for that interface and giving one instance, which adheres to the interface to as an argument to another class/objects's method (e.g. a constructor or a setter or a different method).

I do not see why I should use a dependency injection framework (DIF). What are the advantages (and disadvantages) of using a dependency injection framework, which is no service locator framework?

Details

I read that some framework allow things to be "registered" - but that sounds awfully close to a framework that implements the service locator pattern, not dependency injection. What's up with that? After reading the answers to Why are Service Locator frameworks often called Dependency Injection Containers?, it seems to me that - in fact - DIFs are service locator frameworks and the only part of "dependency injection" is the registration of the services into the framework. Are dependency injection frameworks secretly implementing the service locator pattern after all? One answer says that there is indeed too little benefit of a DIF if it is not a service locator, that is why such a framework does not exist.

More Background (if not important, please ignore it): I am mostly programming in Python. However, I am mostly interested in the general principle.

14
  • 2
    Mark Seeman, widely regarded as an expert on DI Containers, provide a pretty good summary of the pros and cons here. Commented Mar 16, 2021 at 14:41
  • I strongly dislike "dependency injection" because I find that it makes it much more difficult to be certain what the source-code will actually do when executed. But maybe that's just me. Commented Mar 16, 2021 at 15:02
  • 1
    @MikeRobinson: Are you sure you mean the same thing as I do, when I say "dependency injection" and that you do not mean the thing that I call "service locator"?
    – Make42
    Commented Mar 16, 2021 at 15:05
  • 1
  • 1
    See also stackoverflow.com/q/22795459 Commented Mar 16, 2021 at 15:23

1 Answer 1

1

The magic of DI container is to avoid doing a very tiresome manual binding of all your objects. Binding that will need to be updating every time a single thing change.

Whatever is made of your DI container (service locator pattern inside) is not your problem. What matter to you is that it works and you need to explicitly reference the service locator or whatever he's using inside most of the time (except special cases as always).

for instance in Java/Spring I would have :

@Component
public class XX implements IMyInterface{

   @Autowired
   public IMyBean injected;

   @Transactional
   public void save(MyObject toSave){...}
}

Here :

  • @Component indicate to the framework to register this class, by default it will be instantiate only once and as such it must have no state or one that does not change once initialization is done. In the case of Spring, you can eventually control the scope of the instantiation, for instance you can tied it to the current thread, of the current HTTP user session.
  • @Autowired : indicate that I want the DI container to inject a instance that implements the interface IMyBean. If there are more than one candidate i will need to add extra information to help my DI container to resolve it.
  • @transactional : here we are outside of just the DI Containers context, here the framework will automatically open a database transaction for me if one is not already active and commit it after the transaciton (or rollback if there is an exception).

As such we can see that :

  • I don't need to maintain one big main where I initialized everything by hand. Let alone multiple of them if I have a need for. I might still need a main but it will be lighter.
  • By making everything singleton by default, it will avoid multiple instantiation of the same thing if it is not needed
  • A framework can do more than just inject dependency, it can even read annotation in order to avoid classic boilerplate code (get a connection from the pool, open transaction, commit/rollback, release the connection), allowing me to focus on what I want to do.
  • Instead of making a public class, I could have make it package private, so I would only expose my interface (my API) to the code than need to use implementation of the said interface.
  • Standardization : by making every library you might need usable the same way, it's easier to grasp the next dependency you will need to use and that your framework will manage for you.
  • You can also have some way to detect new dependencies and integrate them at runtime (for instance if multiple team works on same large project).

Some of the cons when you start are the following :

  • Cyclic dependecy will make your code crash at runtime and might be not easy to solve (generally it is a design proble).
  • Without a solid grasp of the basics, you will be lost of what is the framework doing for you and why sometimes it behave like it is (for instance, knowing what is a transaction/commit/rollback for relational database). For instance authentication and security isn't an esy topic when you need something solid, so understanding how the framework is doing it for you is also not easy.
  • When it does not work for some reason (configuration, dependencies version problem) it might take some effort to resolve.
8
  • 2
    I find it fascinating that we've immortalized the Singleton (widely regarded as an anti-pattern) in DI containers, but I agree that having the ability to specify lifetime scope is a very useful feature. Commented Mar 16, 2021 at 15:41
  • 1
    @RobertHarvey yeah but I’ll never forgive them for cluttering POJOs with annotations. Commented Mar 16, 2021 at 17:10
  • This is nice example when framework trying to do too much for you :(. Talking about transactional annotation
    – Fabio
    Commented Mar 16, 2021 at 18:02
  • @Fabio their goal seems to be to trick you into using what is effectively a new language. One that specializes in something called vender lock in. I mean, they don’t force you down that path. But they make it awfully easy. Commented Mar 16, 2021 at 23:30
  • @RobertHarvey the downsides of singleton when they're not done with DI container is the hard dependencies and hard call to "MyServiceImpl.getInstance()", since the DI do it for you without needing to have direct dependencies, you do not have that downside of the Singleton pattern.
    – Walfrat
    Commented Mar 17, 2021 at 9:16

Not the answer you're looking for? Browse other questions tagged or ask your own question.