Как стать автором
Обновить

Комментарии 11

Async — да, используем, для методов вынесенных в отдельный бин (что-то наподобие job'ов), вызывать которые может понадобится в нескольких местах или по расписанию (например, используя @Schedule).

Вы это пробовали? Работает? Знали об этом способе?

1) Это решение оправдавшее себя в проекте.
kefirfromperm развернул решение, на которое я мягко намекал :)
Проблема как раз в том, что вызывается метод того же класса. Таким образом, на него не накладываются аспекты. docs.spring.io/spring/docs/4.0.5.RELEASE/spring-framework-reference/htmlsingle/#aop-understanding-aop-proxies

Ваше решение плохо тем, что:
1. создание транзакции привязано к вызову метода, а не к определению метода;
2. если на методе навешаны дополнительные аспекты, то они не будут работать.

Решений здесь 3:
1. вынести метод в отдельный класс;
2. через контекст получать proxy и вызывать на нем наш метод;
3. скомпилировать всё в AspectJ.

Все они не лишены недостатков, но более универсальны, чем написание своего TaskExecutor.

Добрый день,
Решений здесь 3:
1. вынести метод в отдельный класс;

Метод вынести можно, если это приемлемо для архитектуры (есть другой бин, в которм он будет смотреться гармонично). А что, если этот метод задумывался как правит? Или ещё часто бывает, что асинхронно нужно вызвать пару строк, которые в метод оформлять совсем не хочется.

2. через контекст получать proxy и вызывать на нем наш метод;

Когда-то разрабатывая EJB bean, я делал вот так:
@Stateless
public class FooServiceImpl implements FooService {
       @EJB
       private FooService fooService;

       @TransactionAttribute
        public void method1() {
               // some operations
               fooService.method2(); 
        }
      
         @TransactionAttribute
         @Asynchronous
        public void method2() {
               // some high load operations
        } 
}

Выглядит как hook или workaround; не стал бы рекомендовать кому-либо так делать.

3. скомпилировать всё в AspectJ.

Тоже вариант. Однако, сделать универсальный Аспект, субъективно, сложнее чем унивесальный TaskExecutor.
Здесь да, универсального решения нет.
Виталь, а что тебе в 3-м варианте не нравится, кроме того, что немного повозиться с настройками надо? У Сереги и у меня на проекте это решило проблему с прокси, пока работает и устраивает. Позволяет указать настройку в одном месте и забыть о каких-либо правилах вызова одного метода из другого.
У меня какой-то внутренний страх перед AspectJ. :)
Я считаю первый способ близким к идеальному.
Всегда можно сделать пометку в комментариях, что на самом деле метод «приватный».
Важно то, что не придется писать и поддерживать лишнюю кучу кода.
3-й вариант вполне универсальный. По крайней мере, проблем с прокси не возникнет. Создавать какие-либо аспекты тоже не требуется. Посмотрите настройку "<tx:annotation-driven mode=«aspectj»/>"
Quadrix, mode=«aspectj» решит вопрос с вызовом транзакционного метода (@Transactional) в том же классе. Но не забываем про асинхронность, если уходить от использования TaskExecutor, то потребуется @Async, а для её обработки по-прежнему нужен dynamic proxy.

В целом смысл всего этого — дать варинт исполнения произвольного кода(не обязательно метода того же класса) асинхронно и в рамках транзакции. Т.е. посыл такой — если Вы используете TaskExecutor, но не хватает транзакционности, то статья даёт решение.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации