DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workkloads.

Secure your stack and shape the future! Help dev teams across the globe navigate their software supply chain security challenges.

Releasing software shouldn't be stressful or risky. Learn how to leverage progressive delivery techniques to ensure safer deployments.

Avoid machine learning mistakes and boost model performance! Discover key ML patterns, anti-patterns, data strategies, and more.

Related

  • Actuator Enhancements: Spring Framework 6.2 and Spring Boot 3.4
  • How Spring Boot Starters Integrate With Your Project
  • A Practical Guide to Creating a Spring Modulith Project
  • Structured Logging in Spring Boot 3.4 for Improved Logs

Trending

  • Recurrent Workflows With Cloud Native Dapr Jobs
  • A Modern Stack for Building Scalable Systems
  • Beyond Linguistics: Real-Time Domain Event Mapping with WebSocket and Spring Boot
  • Mastering Fluent Bit: Installing and Configuring Fluent Bit on Kubernetes (Part 3)
  1. DZone
  2. Coding
  3. Frameworks
  4. Effective Advice on Spring Async: Part 1

Effective Advice on Spring Async: Part 1

Learn more about the limitations when using Spring Async.

By 
Shamik Mitra user avatar
Shamik Mitra
·
Mar. 13, 19 · Presentation
Likes (18)
Comment
Save
Tweet
Share
52.0K Views

Join the DZone community and get the full member experience.

Join For Free

As per the current trend, I see developers from Juniors to Seniors all using Spring Boot as their weapon of choice to build software. The fact that it is developer friendly and its "convention over configuration" style helps the developer to only focus on business logic. If they are unsure as to how Springs works, just reviewing a Spring Boot tutorial can allow one to start using Spring Boot — it's that easy. Review a related tutorial covering how to implement OAuth 2.0 with Spring Boot.

Another part of Spring Boot that I like is that developers do not have to know Spring's inner details — just put some annotations in, write the business code, and voila! With that said, sometimes, you have to know how it works. What I am trying to say is that you need to know your tool better so you can utilize it like a pro. DZone's previously covered how to implement Spring Boot Security for Swagger.

In this article, I will attempt to give you a better idea as to how you can use asynchronous processing in Spring.

Any pieces of logic that are not directly associated with business logic (cross-cutting concerns) or logic that has a response not needed in the invoker context to determine the next flow or any business computation are ideal candidates for asyncronization. Also, when integrating to a distributed system, the asyncronization technique is being used to make them decoupled.

In Spring, we can use asynchronization using the @Async annotation. But if you use randomly @Async on top of a method and think your method will be invoked as asynchronous in a separate thread, you are wrong. You need to know how @Async works and it's limitations. Without that, you can't understand Async behavior.

How Does @Async Work?

When you put an Async annotation on a method underlying it, it creates a proxy of that object where Async is defined (JDK Proxy/CGlib) based on the proxyTargetClass property. Then, Spring tries to find a thread pool associated with the context to submit this method's logic as a separate path of execution. To be exact, it searches a unique TaskExecutor bean or a bean named as taskExecutor. If it is not found, then use the default SimpleAsyncTaskExecutor.

Now, as it creates a proxy and submits the job to the TaskExecutor thread pool, it has a few limitations that have to know. Otherwise, you will scratch your head as to why your Async did not work or create a new thread! Let's take a look.

Limitations of @Async 

1. Suppose you write a class and identify a method that will act as Async and put @Async on top of that method. Now, if you want to use that class from another class by creating local instance, then it will not fire the async. It has to be picked up by Spring @ComponentScan annotation or created inside a class marked  @Configuration.

Async Annotation Uses in a Class

package com.example.ask2shamik.springAsync.demo;

import java.util.Map;

import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
@Component
public class AsyncMailTrigger {

@Async
public void senMail(Map<String,String> properties) {
System.out.println("Trigger mail in a New Thread :: "  + Thread.currentThread().getName());
properties.forEach((K,V)->System.out.println("Key::" + K + " Value ::" + V));
}

}


Caller Class

package com.example.ask2shamik.springAsync.demo;

import java.util.HashMap;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class AsyncCaller {

@Autowired
AsyncMailTrigger asyncMailTriggerObject;

public void rightWayToCall() {
System.out.println("Calling From rightWayToCall Thread " + Thread.currentThread().getName());
asyncMailTriggerObject.senMail(populateMap());

}

public void wrongWayToCall() {
System.out.println("Calling From wrongWayToCall Thread " + Thread.currentThread().getName());
AsyncMailTrigger asyncMailTriggerObject = new AsyncMailTrigger();
asyncMailTriggerObject.senMail(populateMap());
}

private Map<String,String> populateMap(){
Map<String,String> mailMap= new HashMap<String,String>();
mailMap.put("body", "A Ask2Shamik Article");
return mailMap;

}
}


Here, I created two methods — one used the @Autowired version of AsyncMailtrigger, which will be picked by @ComponentScan, but in a  WrongWayToCall method, I create the object in local, so it will not be picked up by @ComponentScan, and hence, it will not spawn a new thread and will be executed inside the main thread.

Outcome

Calling From rightWayToCall Thread main
2019-03-09 14:08:28.893  INFO 8468 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
Trigger mail in a New Thread :: task-1
Key::body Value ::A Ask2Shamik Article
++++++++++++++++
Calling From wrongWayToCall Thread main
Trigger mail in a New Thread :: main
Key::body Value ::A Ask2Shamik Article


2. Never use @Async on top of a private method. In runtime, it will not able to create a proxy and, therefore, not work.

@Async
private void senMail() {
System.out.println("A proxy on Private method "  + Thread.currentThread().getName());

}


3. Never write an Async method in the same class where the caller method invokes the same Async methodAsync method in the same class where the caller method invokes the same Async method. So, always remember that when using this reference, Async does not work because, in this case, although it creates a proxy, the call bypasses the proxy and directly call the method so that Thread will not be spawned. This will prevent the developer from having the wrong assumption that it will work in an Async fashion. Most developers carelessly implement Async in this way, so be very careful when writing the Async caller method. It should be in a different class when calling the Async method.

Ask2shamik Async Invocation

Example

package com.example.ask2shamik.springAsync.demo;

import java.util.HashMap;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
@Component
public class AsyncCaller {

@Autowired
AsyncMailTrigger asyncMailTriggerObject;

public void rightWayToCall() {
System.out.println("Calling From rightWayToCall Thread " + Thread.currentThread().getName());
asyncMailTriggerObject.senMail(populateMap());

}

public void wrongWayToCall() {
System.out.println("Calling From wrongWayToCall Thread " + Thread.currentThread().getName());
this.senMail(populateMap());
}

private Map<String,String> populateMap(){
Map<String,String> mailMap= new HashMap<String,String>();
mailMap.put("body", "A Ask2Shamik Article");
return mailMap;

}

@Async
public void senMail(Map<String,String> properties) {
System.out.println("Trigger mail in a New Thread :: "  + Thread.currentThread().getName());
properties.forEach((K,V)->System.out.println("Key::" + K + " Value ::" + V));
}

}


The last piece of advice is to execute the application. Please note that we use the @EnableAsync annotation. With this, Spring submits @Async methods in a background thread pool. This class can customize the used Executor by defining a new bean. I will explore this later with an example of how to do that in part two.

package com.example.ask2shamik.springAsync;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.annotation.EnableAsync;

import com.example.ask2shamik.springAsync.demo.AsyncCaller;

@SpringBootApplication
@EnableAsync
public class DemoApplication {

@Autowired
AsyncCaller caller;

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

}
 @Bean
 public CommandLineRunner commandLineRunner(ApplicationContext ctx) {
        return args -> {
        caller.rightWayToCall();
        Thread.sleep(1000);
        System.out.println("++++++++++++++++");
        Thread.sleep(1000);
        caller.wrongWayToCall();

        };
    }
}


Conclusion

Well, I hope you are now able to understand how Async works internally and some of its limitation. In my next article, I will discuss how an exception handler works in Async. Stay tuned!

Spring Framework Spring Boot Advice (programming)

Published at DZone with permission of Shamik Mitra, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Actuator Enhancements: Spring Framework 6.2 and Spring Boot 3.4
  • How Spring Boot Starters Integrate With Your Project
  • A Practical Guide to Creating a Spring Modulith Project
  • Structured Logging in Spring Boot 3.4 for Improved Logs

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!