Reputation: 987
So I have my Subject class:
@Component
public class Subject<T extends Monitorable> {
@Autowired
private List<Observer<T>> observers;
public void fireListeners(T monitorable){
for (Observer<T> observer : observers) {
observer.doSome(monitorable);
}
}
}
Is that a way to create a new subject instance for each implementation of Monitorable like:
@Autowired
private Subject<Trip> tripSubject;
Trip is a Monitorable and it has its own observers
@Autowired
private Subject<Truck> truckSubject;
and truck as well
The problem is. It creates only one Subject with all observers mixed how to separate them without create a new subject class for each monitorable?
Upvotes: 3
Views: 277
Reputation: 987
I improved oleg.cheredinik answer because there is no way to do it. Here's what I think is the best solution:
I changed Subject to receive Observer as construct params
public class Subject<T extends Monitorable> {
private final List<Observer<T>> observers;
public Subject(final List<Observer<T>> observers) {
this.observers = observers;
}
public void fireListeners(T monitorable){
for (Observer<T> observer : observers) {
observer.doSome(monitorable);
}
}
}
and then I created subject with SubjectSimpleFactory :
@Configuration
public class SubjectSimpleFactory {
@Bean
@Autowired(required = false)
public Subject<Trip> getTripSubject( Optional<List<Observer<Trip>>> observers){
return new Subject<>(getListenersIfPresent(observers));
}
@Bean
@Autowired(required = false)
public Subject<Truck> getTruckSubject( Optional<List<Observer<Truck>>> observers){
return new Subject<>(getListenersIfPresent(observers));
}
}
private static <M extends Monitorable> List<Observer<M>> getListenersIfPresent(
final Optional<List<Observer<M>>> observers )
{
return observers.isPresent() ? observers.get() : Collections.emptyList();
}
In this way my observers are not mixed and I only have to create one class without repeat code or subclass Subject and I can use generic type as qualifier as well
Upvotes: 1
Reputation: 1764
@Service
@Scope("prototype")
public class Subject<T extends Monitorable> {
}
@Component
public class RunSubject {
@Autowired
private Subject<Monitorable1> subject1;
@Autowired
private Subject<Monitorabl2> subject2;
public void run(ApplicationArguments args) throws Exception {
System.out.println(subject1);
System.out.println(subject2);
}
}
Upvotes: 0
Reputation: 18255
It is pretty simple. You could do it in a few ways, one of them is just create @Configuration
and defind separate method for each required instance.
First, do remove @Component
annotation from Subject
definition:
//@Component
public class Subject<T extends Monitorable> {
}
Second, do define custom configuration with @Configuration
:
@Configuration
public class MonitorableConfiguration {
@Bean
public Subject<Trip> tripSubject() {
return new Subject<>();
}
@Bean
public Subject<Truck> documentSubject() {
return new Subject<>();
}
}
Third, do use @Qualified
to select required instance of Subject
bean:
@Service
public class BusinessLogicService {
@Autowired
@Qualifier("tripSubject")
private Subject<Trip> tripSubject;
@Autowired
@Qualifier("documentSubject")
private Subject<Truck> documentSubject;
}
NOTE In this situation, I would reccomend to go a little bit further. It could be more readable from my point of view.
First, do remove @Component
annotation from Subject
definition:
//@Component
public class Subject<T extends Monitorable> {
}
Second, do declare separate class
definition for all required types:
@Component
public class TripSubject extends Subject<Trip> {
}
@Component
public class TruckSubject extends Subject<Truck> {
}
Third use is as any other singletons cope beans:
@Service
public class BusinessLogicService {
@Autowired
private TripSubject tripSubject;
@Autowired
private TruckSubject documentSubject;
}
Upvotes: 1
Reputation: 120851
This is not the answer to your question, but maybe a solution for your problem: Spring 4.2 has a build in event (observer) mechanism :
@Autowire ApplicationEventPublisher publisher;
public void doSomething() {
...
//fire the event
publisher.publishEvent(new YourEvent());
...
}
Some other bean:
//This is the observer, it "catch" the event
@EventListener
public void handleOrderCreatedEvent(YourEvent your) {
...
}
Upvotes: 1