Метод Spring @Async внутри службы

у меня есть этот компонент службы с методом синхронизации, вызывающим внутренний асинхронный метод:

@Service
public class MyService {

    public worker(){
        asyncJob();
    }

    @Async
    asyncJob(){
        ...
    }

}

проблема в том, что asyncJob на самом деле не вызывает асинхронным способом. Я обнаружил, что это не работает, потому что внутренний вызов пропускает прокси AOP.

поэтому я стараюсь self-refer Боб:

@Service
public class MyService {

    MyService mySelf;
    @Autowired
    ApplicationContext cnt;
    @PostConstruct
    public init(){
        mySelf=(MyService)cnt.getBean("myService");
    }


    public worker(){
        mySelf.asyncJob();
    }

    @Async
    asyncJob(){
        ...
    }

}

это не. Снова нет асинхронного вызова.

поэтому я попытался разделить в два бобы:

@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(){
        ...
    }

}

но в этом случае это служебная работа... почему я не могу позвонить ему со службы?

2 ответов


нашел действительно хороший способ решить эту проблему (с java8) в случае, когда у вас есть много различных вещей, которые вы хотите синхронизировать и асинхронно. Вместо создания отдельного XXXAsync service для каждой "синхронной" службы создайте общую асинхронную оболочку службы:

@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
    }

}

Я решил третий метод (разделите его на два компонента), переключив модификатор асинхронного метода на общественные

@Service
public class MyService {
    @Autowired
    MyAsyncService myAsyncService;
    public worker(){
        myAsyncService.asyncJob();
    }
}

@Service
public class MyAsyncService {

    @Async
    public asyncJob(){ // switched to public
        ...
    }

}