0

Here is my code to work with @Async with CompletableFuture in Spring Boot:

@RestController
@EnableAsync
public class DemoController {

@Autowired
UtilService service;

    
@GetMapping("/test/{count}")
public void test(@PathVariable int count) throws InterruptedException, ExecutionException {
    List<CompletableFuture<String>> list = new ArrayList<>();
    long start = System.currentTimeMillis();
    for(int i=0; i< count; i++) {
        //CompletableFuture<String> res = calculate(i);
        CompletableFuture<String> res = service.calculate(i);
        list.add(res);
        
    }
    List<String> res = list.stream().map(com -> com.join()).collect(Collectors.toList());
    res.forEach(System.out:: println);
    System.out.println("Elapsed time: " + (System.currentTimeMillis() - start));

}



@Async
public CompletableFuture<String> calculate(int counter) throws InterruptedException{

  Thread.sleep(1000L);
  System.out.println("------Util------counter->" + counter);
  return CompletableFuture.completedFuture("Async -" + counter);
  
}
}


@Service
public class UtilService {


    @Async
    public CompletableFuture<String> calculate(int counter) throws InterruptedException{

      Thread.sleep(1000L);
      System.out.println("------Util------counter->" + counter);
      return CompletableFuture.completedFuture("Async -" + counter);
      
   }


 }

When i keep the async method calculate() in the same contrller class, code is not executing in asynchronus way. it is running as a synchronus method. But when i move the async method calculate() to a different component. It is working fine.

I didnt understand why there is behavour change. if both methods (calling, caller) are in same class, code is running synchronusly. if both methods (calling, caller) are in different classes, code is running in asynchronusly.

Could you any one explain me is there any reason behind.

Thirumal
  • 8,280
  • 11
  • 53
  • 103
Satya
  • 8,146
  • 9
  • 38
  • 43
  • `@EnableAsync` annotation should be used together with `@Configuration` classes. Can you try removing the `@EnableAsync` from your RestController and putting it on your main class that is annotated with `@SpringBootApplication`? – Abhinav Aug 06 '22 at 08:27
  • check out a workaround here: https://stackoverflow.com/a/73007337/804521 – Yevgeniy Aug 06 '22 at 09:01

1 Answers1

1

For the same reason that the @Transactional Annotation only works in a Subclass and not the same Class.

Spring creates Proxies around your Services. Some Annotations only can be used when the proxy intercepts the call and the execute the code. Does Spring @Transactional attribute work on a private method?

Static code analysis (e.g. Sonar) should warn you about such Annotations that not used.

GJohannes
  • 1,408
  • 1
  • 8
  • 14