3

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?

  • I am not familiar with autowiring. Can you have X classes being a Subject and Y classes being an Observer, where each Observer receives notifications from a different set of Subjects? Because that is a very common usecase for the Observer pattern (multiple instances of the pattern all over the codebase). – Bart van Ingen Schenau May 10 '20 at 18:19
  • @BartvanIngenSchenau Autowiring is dependency injection provided by the container, similar to @Inject in JavaEE environments. And yes, each observer may be provided to multiple subjects: EmitsSomething could be a concrete Subject, and Y implements ReceivesSomething, ReceivesSomethingElse might be an observer for this subject that also observes notifications from another subject. – C-Otto May 10 '20 at 19:02
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.

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.

  • I prefer constructor injection over field/setter injection so that it is impossible to have cyclic dependencies. Why do you think it is a good idea to relax this requirement? I know that non-constructor injection (or maybe something like @Lazy) would help. – C-Otto May 10 '20 at 15:44
  • I do too. But you physically can’t create cycles with constructors. It’s one of the reasons I like constructors. I’m not questioning the constructor. I’m questioning the cycle. You can’t be immutable with this stupid setter either. But none of this is fixed by adding a C. – candied_orange May 10 '20 at 15:50
  • 1
    It’s you observer with the “transitive dependency on the subject” that’s spoiling your immutable fun. – candied_orange May 10 '20 at 15:54
  • The observer has good reasons to have the transitive dependency (example: is notified about event "X for 123" and needs to create an event "X for 456"). However, the code that creates those events (the subject) does not need to know anything about the observers. So, no, I don't think the transitive dependency on the subject is the issue, although of course every edge on the cycle is part of the problem. – C-Otto May 10 '20 at 19:20
  • @C-Otto it is the issue if you want construction code to establish it. Setter injection can but constructors can’t. – candied_orange May 10 '20 at 20:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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