I'm new to asynchronous task execution in Spring, so please forgive me if this sounds like a silly question.
I read that @Async annotation is introduced from Spring 3.x onward at method level to invocation of that method will occur asynchronously. I also read that we can configure the ThreadPoolTaskExecutor in the spring config file.
What I'm not able to understand is that how to call a @Async annotated method from a tak executor lets suppose - AsyncTaskExecutor
Earlier we used to do something like in a class:
@Autowired protected AsyncTaskExecutor executor;
And then
executor.submit(<Some Runnable or Callable task>)
I'm not able to understand the relationship between @Async annotated methods and TaskExecutor.
I tried searching a lot over the internet but could not get anything on this.
Can somebody provide an example for the same.
Complete Example
Config Spring
@Configuration
@EnableAsync
@ComponentScan("com.async")
public class AppConfig {
@Bean
public AsyncManager asyncManger() {
return new AsyncManager();
}
@Bean
public AsyncExecutor asyncExecutor() {
return new AsyncExecutor();
}
}
Executor Class Created, Executor i have created so that spring takes care of thread management.
public class AsyncExecutor extends AsyncConfigurerSupport {
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(2);
executor.setMaxPoolSize(2);
executor.setQueueCapacity(500);
executor.setThreadNamePrefix("Violation-");
executor.initialize();
return executor;
}
}
Create a manager.
public class AsyncManager {
@Autowired
private AsyncService asyncService;
public void doAsyncTask(){
try {
Map<Long, ViolationDetails> violation = asyncService.getViolation();
if(!org.springframework.util.CollectionUtils.isEmpty(violation)){
violation.entrySet().forEach( violationEntry -> {System.out.println(violationEntry.getKey() +"" +violationEntry.getValue());});
}
System.out.println("do some async task");
} catch (Exception e) {
}
}
}
Configure your service class.
@Service
public class AsyncService {
@Autowired
private AsyncExecutor asyncExecutor;
@Async
public Map<Long,ViolationDetails> getViolation() {
// TODO Auto-generated method stub
List<Long> list = Arrays.asList(100l,200l,300l,400l,500l,600l,700l);
Executor executor = asyncExecutor.getAsyncExecutor();
Map<Long,ViolationDetails> returnMap = new HashMap<>();
for(Long estCode : list){
ViolationDetails violationDetails = new ViolationDetails(estCode);
returnMap.put(estCode, violationDetails);
executor.execute((Runnable)new ViolationWorker(violationDetails));
}
return returnMap;
}
}
class ViolationWorker implements Runnable{
private ViolationDetails violationDetails;
public ViolationWorker(ViolationDetails violationDetails){
this.violationDetails = violationDetails;
}
@Override
public void run() {
violationDetails.setViolation(System.currentTimeMillis());
System.out.println(violationDetails.getEstablishmentID() + " " + violationDetails.getViolation());
}
}
Model.
public class ViolationDetails {
private long establishmentID;
private long violation;
public ViolationDetails(long establishmentID){
this.establishmentID = establishmentID;
}
public long getEstablishmentID() {
return establishmentID;
}
public void setEstablishmentID(long establishmentID) {
this.establishmentID = establishmentID;
}
public long getViolation() {
return violation;
}
public void setViolation(long violation) {
this.violation = violation;
}
}
Test to Run
public class AppTest {
public static void main(String[] args) throws SQLException {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(AppConfig.class);
ctx.refresh();
AsyncManager task= ctx.getBean(AsyncManager.class);
task.doAsyncTask();
}
}
Here's an example of @Async
use:
@Async
void doSomething() {
// this will be executed asynchronously
}
Now call that method from another class and it will run asynchronously. If you want a return value use a Future
@Async
Future<String> returnSomething(int i) {
// this will be executed asynchronously
}
The relationship between @Async
and TaskExecutor
is that @Async
uses a TaskExecutor
behind the scenes. From the docs:
By default when specifying @Async on a method, the executor that will be used is the one supplied to the 'annotation-driven' element as described above. However, the value attribute of the @Async annotation can be used when needing to indicate that an executor other than the default should be used when executing a given method.
So to set up a default executor, add this to your spring config
<task:annotation-driven executor="myExecutor" />
Or to use a particular executor for a single use try
@Async("otherExecutor")
See http://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/scheduling.html#scheduling-annotation-support-async
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With