5

In my project I'm using the observer pattern in several places, i.e. the subject notifies the observers about something, and expect them to act. The subject does not know anything about the details of these observers.

With Spring I autowired/injected the observers as follows (constructor injection):

@Autowired public Subject(List<Observer> observers) {...}

This works, and as Observer is an interface, there's no compile-time dependency from Subject to Observer. However, there needs to be a runtime dependency, so that the observers can be notified by the subject.

With the approach shown above, I experienced bean dependency cycle issues, as one of the observer's transitive dependencies was the subject itself.

To fix this, I introduced a new class SubjectInitializer (and changed the Subject accordingly):

@Autowired
public SubjectInitializer(Subject subject, List<Observer> observers) {
    subject.addObservers(observers);
}

This way I don't have any bean dependency cycle, as SubjectInitializer is not the target of any dependency.

However, this fix seems weird to me:

  1. The observer pattern is used quite a lot, so I guess there's a lot of experience on how to use it with Spring. However, I didn't find anything helpful.
  2. The whole purpose of the SubjectInitializer is to initialize the Subject, which only has to happen once. Creating a new bean (and having the singleton in memory?) seems over the top.

Is there a better way to autowire the observer instances?

C-Otto
  • 169

3 Answers3

1

The problem is that you wanted to use constructors. You can’t create cyclic dependencies with constructors, which normally, is a good thing.

What you need is a setter so that after you build A without B and build B with A you can then introduce B to A. You don’t need to invent a C.

This problem has nothing to do with spring. It’s a constructor thing.

candied_orange
  • 119,268
1

What you’re looking at is a chicken and egg situation. You can’t have your cake and eat it too in this case.

If A needs B and B needs A at construction time you’re basically stuck. Haven’t used Spring in ages, but if it is indeed supported it’s almost certainly implemented through property injection and/or reflection or other dynamic approach behind the scenes.

If you’re concerned about the purity/fragility of the design, it’s worth looking into method injection. That is, maybe the dependency is only needed to perform one or two specific functions. If that’s the case, as opposed to the dependency playing a more central role and needed in many places, then one could argue that method injection is in fact better since it’s only being brought in when needed as a parameter and not as part of the object that needs it itself.

joakim
  • 196
1

As this Observer depends on the Subject, the best seems to invert the setup of observable pattern: this Observer takes the subject in its constructor, then let it add itself as observer: subject.addObserver(this)

This way, there's no dependency circle, both dependencies go the same way.