Еще в Spring 1.2 была возможность посылать различные event-ы через весь контекст приложения. Я считаю этот вид коммуникации в некоторых местах приложения единственным верным решением.
Опишу кратко как работает этот механизм. Базовым классом для event-а должен быть org.springframework.context.ApplicationEvent
, для рассылки которого используется метод org.springframework.context.ApplicationContext.publishEvent(event)
. Ну а получать event-ы будут те bean-ы, которые реализуют интерфейс org.springframework.context.ApplicationListener
с единственным методом onApplicationEvent(event)
.
Допустим, что у нас есть логика, после выполнения которой другим сервисам необоходимо также сделать какие-то действия. Стандартный вариант решения такой задачи предполагает использование IoC:
public class BussinesServiceImpl implements BussinesService {
@Autowired
private EmailService emailService;
@Autowired
private LoggingService logService;
public void doAction() {
...
emailService.sendEmail(email, body);
logService.recordLog(data);
}
}
Также можно использовать и аспекты. Только вот получать параметры, которые пришли не через аргументы метода, advice-ам будет сложно. Реализовать такой случай с помощью event-ов можно так:
public class BussinesServiceImpl implements BussinesService, ApplicationContextAware {
private ApplicationContext context;
public void doAction() {
...
ActionEvent event = new ActionEvent();
event.setEmail(email);
event.setEmailBody(body);
event.setData(data);
context.publishEvent(event);
}
public void setApplicationContext(ApplicationContext value) {
context = value;
}
}
Соответственно сами сервисы будут выглядеть так:
public class EmailServiceImpl implements EmailService, ApplicationListener {
...
public void onApplicationEvent(ApplicationEvent event) {
if (!(event instanceof ActionEvent)) {
return;
}
ActionEvent actionEvent = (ActionEvent) event;
sendEmail(actionEvent.getEmail(), actionEvent.getEmailBody());
}
}
public class LoggingServiceImpl implements LoggingService, ApplicationListener {
...
public void onApplicationEvent(ApplicationEvent event) {
if (!(event instanceof ActionEvent)) {
return;
}
ActionEvent actionEvent = (ActionEvent) event;
recordLog(actionEvent.getData());
}
}
Какое преимущество дает такой подход? Изоляцию сервиса, от лишних зависимостей. Такая изоляция дает возможность выносить сервисы типа BussinesService
в отдельные модули, которые не потребуют в дальнейшем модификации, если понадобится добавить вызов какого-либо сервиса.