I have a requirement to use same thread for multiple request in async spring.
Here is the code which i am using :
Here is the Executor configuration file
#Configuration
#EnableAsync
public class ExecutorConfig {
#Bean(name = "threadPoolExecutor")
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(7);
executor.setMaxPoolSize(42);
executor.setQueueCapacity(11);
executor.setThreadNamePrefix("threadPoolExecutor-");
executor.initialize();
return executor;
}
}
Here is the service file
public interface QueueService {
public void createQueue();
public void sendData();
}
Here is the Service Implementation
#Service
public class QueueServiceImpl implements QueueService {
#Override
#Async("threadPoolExecutor")
public void createQueue() {
System.out.println(Thread.currentThread().getName());
}
#Override
#Async("threadPoolExecutor")
public void sendData() {
// Need to use the same thread which created the queue
// Thread.currentThread() should be same for both methods
System.out.println(Thread.currentThread().getName());
}
}
Here is the controller class
#RestController
public class Controller {
#Autowired
QueueService queueService;
#RequestMapping(value="/create", method = RequestMethod.GET)
public void createQueue()
{
queueService.createQueue();
}
#RequestMapping(value="/send", method = RequestMethod.GET)
public void sendDataToQueue()
{
queueService.sendData();
}
}
Here is the Spring boot main application
#EnableAsync
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Please let me know how to use #Async in 2 separate request to do the job done by same thread.
Related
I need to use autowired in more than one class with ScheduledExecutorService, what I have tried is shown in this code. logging size of User list in below example always shows 0, even after user added to arraylist. How to properly use Autowired and ScheduledExecutorService in spring boot?
#Component
public class AnotherClass {
List<User> users = new ArrayList();
public void addUser(User user){
users.add(user);
}
public void logUsers(){
logger.info("User size " + users.size()); <================= Always logs 0, when called from executor
}
}
#RestController
public class SecondClass {
#Autowired
private AnotherClass anotherClass;
#GetMapping(value="/user/test")
public void logUsers(){
anotherClass.addUser(new User());
}
}
Application Class
#Component
#SpringBootApplication
public class SpringBootDemoApplication {
private ScheduledExecutorService exec = Executors.newScheduledThreadPool(1);
#Autowired
private AnotherClass anotherClass;
#PostConstruct
public void init() {
logger();
}
public static void main(String[] args) {
SpringApplication.run(SpringBootDemoApplication.class, args);
}
public void logger(){
exec.scheduleAtFixedRate(new Runnable(){
#Override
public void run(){
try {
anotherClass.logUsers();
}catch (Exception e){
}
}
}, 2000, 1000, TimeUnit.MILLISECONDS);
}
}
The code works if you use the Spring #Autowired and not the #AutoWired Annotation.
I do some initializations in a CommandLineRunner's run function and I want my Scheduled task to begin schedule after the initialization, how can I achive this?
For example, I have the CommandLineRunner:
#Component
public class MyCommandLineRunner implements CommandLineRunner {
#Override
public void run(String... args) throws Exception {
// Initializations
// ...
}
}
And the task scheduler:
public class SchedClass {
#Scheduled(fixedRate = ONE_SECOND)
public void sched() {
}
}
What can I do to make sched() runs after run() runs?
class MySchedulingConfigurer implements SchedulingConfigurer {
private ScheduledTaskRegistrar taskRegistrar;
private IntervalTask task;
public MySchedulingConfigurer(IntervalTask task) {
this.task = task;
}
#Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
this.taskRegistrar = taskRegistrar;
}
public void resume() {
this.taskRegistrar.scheduleFixedRateTask(task);
}
}
#Configuration
class SchedulerConfiguration {
#Autowired
private MySchedulingConfigurer schedulingConfigurer;
#Bean
public MySchedulingConfigurer mySchedulingConfigurer() {
IntervalTask task = new IntervalTask(new MyTask(), 5000L);
return new MySchedulingConfigurer(task);
}
public static class MyTask implements Runnable {
#Override
public void run() {
System.out.println("===> task executed...");
}
}
#EventListener
public void startScheduler(ApplicationReadyEvent event){
schedulingConfigurer.resume();
}
}
#Component
class CacheLoadingRunner implements CommandLineRunner {
#Autowired
private MySchedulingConfigurer schedulingConfigurer;
#Override
public void run(String... args) throws Exception {
schedulingConfigurer.resume();
}
}
1) Add #EnableScheduling
#EnableScheduling
#SpringBootApplication
public class MyCommandLineRunner implements CommandLineRunner {
...
}
2) It makes no sense to denote Spring Boot application with #Component
UPDATED
It could be achieved manually. Provide a TaskScheduler
#Bean
public ThreadPoolTaskScheduler threadPoolTaskScheduler(){
ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
threadPoolTaskScheduler.setPoolSize(5);
threadPoolTaskScheduler.setThreadNamePrefix("ThreadPoolTaskScheduler");
return threadPoolTaskScheduler;
}
Inject it into MyCommandLineRunner along with SchedClass and run
#Component
public class MyCommandLineRunner implements CommandLineRunner {
#Autowired
private ThreadPoolTaskScheduler taskScheduler;
#Autowired
private SchedClass schedBean;
#Override
public void run(String... args) throws Exception {
// ...
taskScheduler.scheduleWithFixedDelay(() -> schedBean.sched(), ONE_SECOND);
// ...
}
}
I have a SpringBootApplication which subscribes to MQTT broker. MQTT messages need to be saved to Database, but I cannot access my #Autowired service.
Exception I get:
Field deviceService in com.example.MqttMessageHandler required a bean of type 'com.example.service.DeviceService' that could not be found.
MQTTApiApplication.java
#SpringBootApplication(scanBasePackages = "{com.example}")
public class MQTTApiApplication {
public static void main(String[] args) {
SpringApplicationBuilder(MQTTApiApplication.class)
.web(false).run(args);
}
#Bean
public IntegrationFlow mqttInFlow() {
return IntegrationFlows.from(mqttInbound())
.handle(new MqttMessageHandler())
.get();
}
}
MqttMessageHandler.java
public class MqttMessageHandler extends AbstractMessageHandler {
#Autowired
DeviceService deviceService;
#Override
protected void handleMessageInternal(Message<?> message) throws Exception {
deviceService.saveDevice(new Device());
}
}
Application.java
#SpringBootApplication
public class MQTTApiApplication {
public static void main(String[] args) {
SpringApplication.run(MQTTApiApplication.class, args);
}
#Bean
public IntegrationFlow mqttinFlow(MqttMessageHandler handler) {
return IntegrationFlows
.from(mqttInbound())
.handle(handler).get();
}
}
MqqtMessageHandler.java
#Component
public class MqttMessageHandler extends AbstractMessageHandler{
#Autowired
private DeviceService deviceService;
#Override
protected void handleMessageInternal(String message) {
//...
}
}
DeviceService.java
#Service
public class DeviceService {
#Autowired
private DeviceRepository repository;
//...
}
DeviceController.java
#RestController
#RequestMapping("/")
public class DeviceController {
#Autowired
private IntegrationFlow flow;
//...
}
DeviceRepository.java
#Repository
public class DeviceRepository {
public void save() {
//...
}
}
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.
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.
Use 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
Another way is to use Spring built-in async capabilities
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.
I'm trying to get DI working with a sample DynamoDBTypeConverter I'm playing around with and having no luck at all :( My service is always null and throws an error as a result in my jUnit test.
Here's my converter:
#Component
public class ArmTypeConverter implements DynamoDBTypeConverter<String, Arm> {
#Autowired
private ArmRepository armRepository;
#Override
public String convert(Arm Arm) {
return arm.getId();
}
#Override
public Arm unconvert(String id) {
return armRepository.findOne(id);
}
}
My application main:
#SpringBootApplication
#ComponentScan
#EnableSpringConfigured
#EnableLoadTimeWeaving(aspectjWeaving=EnableLoadTimeWeaving.AspectJWeaving.ENABLED)
#EnableAutoConfiguration
public class ArmApplication implements ApplicationRunner {
public static void main(String[] args) {
SpringApplication.run(ArmApplication.class, args);
}
#Bean
public InstrumentationLoadTimeWeaver loadTimeWeaver() throws Throwable {
InstrumentationLoadTimeWeaver loadTimeWeaver = new InstrumentationLoadTimeWeaver();
return loadTimeWeaver;
}
}
My service:
#Service
public class ArmServiceImpl implements ArmService {
#Autowired
private ArmRepository armRepository;
#Override
public Arm create(String length, Set<Register> registers) {
Date now = new Date();
Arm arm = new Arm();
arm.setLength("85cm");
return armRepository.save(arm);
}
}
My Test:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest
public class ArmServiceTests {
#Autowired
private ArmService armService;
#Autowired
private TorsoService torsoService;
private Arm arm;
#Before
public void before() {
arm = armService.create("85cm", null);
torsoService.create("150cm", arm);
}
#After
public void after() {
// do nothing for now...
}
#Test
#WithUserDetails("admin#somewhere.com")
public void getArmTest() {
Arm c = armService.getArm(arm.getId());
assertThat(c).isNotNull();
assertThat(c.getId()).isEqualTo(arm.getId());
}
}
What am I doing wrong?
The issue was that I didn't have load time weaving configured properly