Quantcast
Channel: Experiences Unlimited
Viewing all articles
Browse latest Browse all 168

The correct way to do @Async in Java Spring based applications

$
0
0

Spring provides an annotation @Async to run tasks in a separate thread. In Spring boot applications we can enable asynchronous tasks by adding the annotation @EnableAsync to any of the Spring configuration class as shown below:

@SpringBootApplication
@EnableAsync
public class AsyncGotchaApplication implements CommandLineRunner {
}

Now that we have the application setup to support asynchronous tasks, let us go ahead and create a simple service that has a method with @Async annotation as shown below:

@Service
@Slf4j
public class AppService {

  public void doSomeWork(){
    log.info("Doing some work...");
    doSomeWorkAsync();
  }
  
  @Async
  public void doSomeWorkAsync(){
    log.info("Doing some work async...");
  }
}

Let us invoke the method doSomeWork() from the main class as shown below:

@SpringBootApplication
@EnableAsync
public class AsyncGotchaApplication implements CommandLineRunner {

  @Autowired AppService appService;

  public static void main(String[] args) {
    SpringApplication.run(AsyncGotchaApplication.class, args);

  }

  @Override
  public void run(String... args) throws Exception {
    appService.doSomeWork();
  }
}

And in the logs, we can see:

In the above logs, we can see that even though the method was annotated as @Async it still runs in the same thread as that of the doSomeWork() method. So something is amiss here.

The catch here is that for a method to be truly asynchronous it has to be in a different class than that of the class in which the method invoking it is defined.

So let us see how this has to be done in the right way. Let us create a service class that has our asynchronous task:

@Service
@Slf4j
public class AppServiceAsync {

  @Async
  public void doSomeWorkAsync(){
    log.info("Doing some work in true async...");
  }
}

And we invoke the method doSomeWorkAsync() from our original AppService class as shown below in lines 11-14:

@Service
@Slf4j
public class AppService {

  @Autowired AppServiceAsync appServiceAsync;

  public void doSomeWork(){
    log.info("Doing some work...");
    doSomeWorkAsync();
  }
  public void doSomeWorkTrueAsync(){
    log.info("Doing some work again...");
    appServiceAsync.doSomeWorkAsync();
  }

  @Async
  public void doSomeWorkAsync(){
    log.info("Doing some work async...");
  }
}

Now let us run the method doSomeWorkTrueAsync() and see how it is different from the first approach:

The working code can be found in the repository https://github.com/sanaulla123/samples/tree/master/async-gotcha


Viewing all articles
Browse latest Browse all 168

Trending Articles