I am working on a solution for which i am trying to create a microservice which returns response immediately and then processes the request.
I am trying to use Java 8 and Spring for this.
ResponseBodyEmitter helps to collect and send the response to the client. It is a controller method return value type for asynchronous request processing where one or more objects are written to the response.
This can be achieved in several ways.
In order to return a result from the current thread (a controller in this case) while still doing some long-running operation, you will need another thread.
Executor
directly.A controller:
@Controller
public class AsyncController {
private AsyncService asyncService;
@Autowired
public void setAsyncService(AsyncService asyncService) {
this.asyncService = asyncService;
}
private ResponseEntity asyncMethod(@RequestBody Object request) {
asyncService.process(new MyLongRunningRunnable());
// returns immediately
return ResponseEntity.ok("ok");
}
}
And a service:
@Service
public class AsyncService {
private ExecutorService executorService;
@PostConstruct
private void create() {
executorService = Executors.newSingleThreadExecutor();
}
public void process(Runnable operation) {
// no result operation
executorService.submit(operation);
}
@PreDestroy
private void destroy() {
executorService.shutdown();
}
}
More details can be found here https://docs.oracle.com/javase/tutorial/essential/concurrency/runthread.html
You can simply annotate a method with @Async
, having void
or Future
return type.
If you still want to supply your own executor, you may implement AsyncConfigurer
interface in your spring configuration bean.
This approach also requires @EnableAsync
annotation.
@Configuration
@EnableAsync
public class AsyncConfiguration implements AsyncConfigurer {
@Override
public Executor getAsyncExecutor() {
return Executors.newSingleThreadExecutor();
}
}
More on this topic https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/scheduling/annotation/Async.html
Here is an example with ExecutorService:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.annotation.PreDestroy;
import javax.servlet.http.HttpServletRequest;
@RestController
public class MyController {
// Instantiate an executor service
private ExecutorService executor = Executors.newSingleThreadExecutor();
@PreDestroy
public void shutdonw() {
// needed to avoid resource leak
executor.shutdown();
}
@GetMapping
public Object gerUrl(HttpServletRequest request) {
// execute the async action, you can use a Runnable or Callable instances
executor.submit(() -> doStuff());
return "ok";
}
private void doStuff(){}
}
You can use the Executors factory class to build a ExecutorService. Those methods might help you:
java.util.concurrent.Executors
Executors.newSingleThreadExecutor() // jobs are queued and executed by a single thread
Executors.newCachedThreadPool() // new threads are instantiated as needed and cached
Executors.newFixedThreadPool(int nThreads) // user defined number of threads
.
@EnableAsync
@SpringBootApplication
public class MyApplication extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(MyApplication.class);
}
public static void main(String[] args) throws Exception {
SpringApplication.run(MyApplication.class, args);
}
}
import javax.annotation.PreDestroy;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurerSupport;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
@Configuration
public class AsyncConfiguration extends AsyncConfigurerSupport {
private ThreadPoolTaskExecutor executor;
@Override
public Executor getAsyncExecutor() {
executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(20);
executor.setMaxPoolSize(50);
executor.setQueueCapacity(1000);
executor.initialize();
return executor;
}
@PreDestroy
public void shutdownExecutors() {
executor.shutdown();
}
}
@Service
public class MyService {
@Async
public void doStuff(){
// Async method
}
}
Both techniques are quite good, but the first one with ExecutorService give you more control.
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