Spring Метод @Async внутри службы
У меня есть эта служба bean с методом синхронизации, вызывающим внутренний метод асинхронного вызова:
@Service
public class MyService {
public worker(){
asyncJob();
}
@Async
asyncJob(){
...
}
}
Проблема в том, что asyncJob на самом деле не вызывает асинхронный путь.
Я обнаружил, что это не работает, потому что внутренний вызов пропускает прокси AOP.
Итак, я пытаюсь самостоятельно присваивать bean:
@Service
public class MyService {
MyService mySelf;
@Autowired
ApplicationContext cnt;
@PostConstruct
public init(){
mySelf=(MyService)cnt.getBean("myService");
}
public worker(){
mySelf.asyncJob();
}
@Async
asyncJob(){
...
}
}
Не удалось. Снова не будет асинхронный вызов.
Итак, я попытался разделить его на два beans:
@Service
public class MyService {
@Autowired
MyAsyncService myAsyncService;
public worker(){
myAsyncService.asyncJob();
}
}
@Service
public class MyAsyncService {
@Async
asyncJob(){
...
}
}
Сбой снова.
Единственный рабочий способ - вызвать его из контроллера Bean:
@Controller
public class MyController {
@Autowired
MyAsyncService myAsyncService;
@RequestMapping("/test")
public worker(){
myAsyncService.asyncJob();
}
}
@Service
public class MyAsyncService {
@Async
public asyncJob(){
...
}
}
Но в этом случае это служебное задание... почему я не могу назвать его из Сервиса?
Ответы
Ответ 1
Я решил третий метод (разделите его на два beans) модификатора Async-метода на public
@Service
public class MyService {
@Autowired
MyAsyncService myAsyncService;
public worker(){
myAsyncService.asyncJob();
}
}
@Service
public class MyAsyncService {
@Async
public asyncJob(){ // switched to public
...
}
}
Ответ 2
Нашел действительно хороший способ решить эту проблему (с помощью java8) в случае, когда у вас есть много разных вещей, которые вы хотите синхронизировать и асинхронить. Вместо создания отдельной службы XXXAsync
для каждой "синхронной" службы, создайте универсальную оболочку асинхронной службы:
@Service
public class AsyncService {
@Async
public void run(final Runnable runnable) {
runnable.run();
}
}
а затем использовать его как таковой:
@Service
public class MyService {
@Autowired
private AsyncService asyncService;
public void refreshAsync() {
asyncService.run(this::refresh);
}
public void refresh() {
// my business logic
}
public void refreshWithParamsAsync(String param1, Integer param2) {
asyncService.run(() -> this.refreshWithParams(param1, param2));
}
public void refreshWithParams(String param1, Integer param2) {
// my business logic with parameters
}
}