У меня есть интерфейс для объекта Service, который выглядит примерно так (упрощенно для краткости):
public interface ItemService {
public Item getItemById(String itemId, int version);
public void create(Item item, User user);
public void update(Item item, User user);
public void delete(Item item, User user);
}
ItemService
единственная реализация и подключен как bean-компонент Spring.Он используется частью пользовательского интерфейса нашего проекта и кодом, который обрабатывает запросы Ajax, для создания и изменения Item
объектов в нашем хранилище данных.
Под капотом каждый метод отправляет серию событийкогда это будет вызвано.События принимаются другими модулями для выполнения таких задач, как обновление индексов Lucene или для отправки сообщений администраторам, чтобы они знали, что что-то изменилось.Каждый вызов метода представляет собой отдельную транзакцию в Spring (с использованием org.springframework.orm.hibernate3.HibernateTransactionManager
и org.springframework.transaction.interceptor.TransactionProxyFactoryBean
).
В последнее время возникла необходимость составить нескольких вызовов методов вместе в одной транзакции.Иногда с более чем одной службой.Например, мы можем захотеть сделать что-то вроде:
*Begin transaction*
Get Items created by User Bill using ItemService
for each Item in Items
Update field on Item
Link Item to User Bill with LinkService
Update Item using ItemService
*Finish transaction*
Мы сделали это, создав другую Службу, которая позволяет вам составлять вызовы от Служб в одном методе в родительской службе.Давайте назовем это ComposingService
.ComposingService
, как и все остальные, также управляется Spring, и, поскольку транзакции реентерабельны, все это должно работать ..
Однако существует проблема: если какая-либо из этих операций внутри транзакции завершится неудачноВ результате отката транзакции мы не хотим отправлять какие-либо события .
В существующем случае, если транзакция завершится неудачей на полпути, половина Событий будет отправлена к ItemService
до того, как транзакция откатится, а это означает, что некоторые модули получат кучу Событий за вещи, которые не произошли,
Мы пытаемся найти способ исправить это, но мы не могли придумать ничего элегантного.Лучшее, что мы придумали до сих пор, это что-то вроде этого (и это уродливо):
public interface ItemService {
public Item getItemById(String itemId, int version);
public void create(Item item, User user, List<Event> events);
public void update(Item item, User user, List<Event> events);
public void delete(Item item, User user, List<Event> events);
}
В этом модифицированном ItemService вместо отправляемых немедленно событий они добавляются в список.События передаются в качестве аргумента.Список поддерживается ComposingService
, а События отправляются ComposingService
после успешного завершения всех вызовов на ItemService
и других служб.
Очевидно, проблема в том, что мы изменили контракт на ItemService безобразно.Вызовам классов, даже если они являются службами, не нужно беспокоиться об управлении событиями.Но я не смог придумать способ обойти это, отсюда и этот вопрос.
Это похоже на проблему, которая, возможно, была решена раньше.У кого-нибудь была проблема, которая выглядит похожей, и если да, то как вы ее решили?