Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring @Async method inside a Service

Tags:

I have this service bean with a sync method calling the internal async method:

@Service public class MyService {          public worker() {         asyncJob();     }          @Async     void asyncJob() {         ...     }      } 

The trouble is that the asyncJob is not really called in async way. I found that this doesn't work because an internal call skips the AOP proxy.

So I try to self-refer the bean:

@Service public class MyService {          MyService mySelf;      @Autowired     ApplicationContext cnt;      @PostConstruct     public void init() {         mySelf=(MyService)cnt.getBean("myService");     }               public void worker() {         mySelf.asyncJob();     }          @Async     void asyncJob() {         ...     }      } 

It fails. Again no async call.

So I tried to divide it in two beans:

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

Fails again.


The only working way is to call it from a Controller Bean:

@Controller public class MyController {      @Autowired     MyAsyncService myAsyncService;      @RequestMapping("/test")     public void worker() {         myAsyncService.asyncJob();     }  }  @Service public class MyAsyncService {      @Async     public void asyncJob() {         ...     }      } 

But in this case it is a service job. Why I cannot call it from a service?

like image 444
Tobia Avatar asked Jul 17 '14 08:07

Tobia


1 Answers

Found a really nice way to solve this (with java8) in the case where you have a lot of various things you want to both sync and async. Instead of creating a separate XXXAsync service for each 'synchronous' service, create a generic async service wrapper:

@Service public class AsyncService {      @Async     public void run(final Runnable runnable) {         runnable.run();     } } 

and then use it as such:

@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     }  } 
like image 95
jlb Avatar answered Oct 04 '22 22:10

jlb