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
    }

}