Spring асинхронный метод, вызванный из другого метода асинхронного

Я использую Spring 4, и я заметил странное поведение... если я вызываю метод async несколько раз из обычного метода экземпляра, то все они вызываются в разных потоках и заканчиваются в произвольные моменты времени, Но если я вызываю несколько раз асинхронный метод из другого метода async, то они заканчиваются по порядку. У меня есть что-то вроде этого:

@Async
public void nonAsyncMethod() {
  for (int i = 0; i < 30; i++) {
     asyncMethod();
  }
}

@Async
public void asyncMethod() {
   ... something here
}

Я использую исполняемый файл async по умолчанию. Должен ли я использовать другой? Однако этот исполнитель не перерабатывает нити и запускает каждый раз каждый раз, так что это должно быть хорошо... Это может быть просто совпадение? Но я пробовал больше, чем 10 раз, и если я вернусь обратно к не-асинхронному для первого метода, они заканчивают случайным образом

Ответы

Ответ 1

То, что вы описываете, является классической ловушкой Spring АОП.

Короче говоря, для Spring для обеспечения асинхронного поведения ему необходимо создать прокси для вашего класса во время выполнения. Затем прокси делает все, что ему нужно сделать до и/или после вызова вашего кода. Но в вашем случае прокси-механизм не применяется для второго метода.

Когда bean вашего класса вводится через Spring в какой-либо другой компонент, Spring действительно вводит прокси вместо этого. Поэтому вызывается соответствующий метод прокси. Однако, когда вы вызываете метод изнутри класса, ограничения Spring AOP означают, что прокси никогда не вступает в игру, но вместо этого вызывается обычный метод - без дополнительных функций.

Вот почему asyncMethod всегда выполняется в том же потоке, что и другой метод в том же классе, который его вызывал.

Отметьте этот отличный пост в блоге, а также this часть документации Spring.

Есть некоторые способы решения проблемы (проверьте этот), которые не требуют рефакторинга вашего кода, но если вы хотите, чтобы async работал над обоими методами независимо от того, что самое простое - это реорганизовать второй метод в другой класс.