Since I investigated what is necessary when performing asynchronous processing with SpringBoot, in this document,
I summarized about.
java8 + Spring Boot 2.1.0 + lombok
build.gradle is as follows
buildscript {
ext {
springBootVersion = '2.1.0.RELEASE'
}
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
dependencies {
implementation('org.springframework.boot:spring-boot-starter-web')
compileOnly('org.projectlombok:lombok')
testImplementation('org.springframework.boot:spring-boot-starter-test')
}
Create a process that just sleeps properly
@Slf4j
@Service
public class AsyncService {
@Async("Thread2")
public CompletableFuture<String> findName(String name, Long sleepTime) throws InterruptedException {
log.warn("Async function started. processName: " + name + "sleepTime: " + sleepTime);
Thread.sleep(sleepTime);
//Use the return value you actually want to use in the Completable Future so that you can handle asynchronous processing.
return CompletableFuture.completedFuture(name);
}
}
Implement an appropriate Controller to handle asynchronous processing
@Slf4j
@RequiredArgsConstructor
@RestController
public class FindNameContoller {
private final AsyncService asyncService;
@GetMapping("/users/")
public List<String> findUsers() throws Exception {
long start = System.currentTimeMillis();
long heavyProcessTime = 3000L;
long lightProcessTime = 1000L;
log.warn("request started");
CompletableFuture<String> heavyProcess = asyncService.findName("heavy", heavyProcessTime);
CompletableFuture<String> lightProcess = asyncService.findName("light", lightProcessTime);
//Process to be executed when heavyProcess is finished
heavyProcess.thenAcceptAsync(heavyProcessResult -> {
log.warn("finished name=" + heavyProcessResult + ", sleep = " + heavyProcessTime);
});
//Process to be executed when lightProcess is finished
lightProcess.thenAcceptAsync(lightProcessResult -> {
log.warn("finished name=" + lightProcessResult + ", sleep = " + lightProcessTime);
});
//When the specified process is completed, the subsequent processes will be executed.
CompletableFuture.allOf(heavyProcess, lightProcess).join();
//Creating a return value
List<String> names = new ArrayList<>();
names.add(heavyProcess.get());
names.add(lightProcess.get());
Thread.sleep(10L);
long end = System.currentTimeMillis();
//Output the time of the entire process
log.warn("request finished. time: " + ((end - start)) + "ms");
return names;
}
}
Describe various settings in the main Application class
@EnableAsync
@SpringBootApplication
public class AsyncTrainingApplication {
public static void main(String[] args) {
SpringApplication.run(AsyncTrainingApplication.class, args);
}
@Bean("Thread1") //This setting is not specified and is not used
public Executor taskExecutor1() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(20);
executor.setThreadNamePrefix("Thread1--");
executor.initialize();
return executor;
}
@Bean("Thread2") //Set here"Thread2"Is set to @Async and that setting is used
public Executor taskExecutor2() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5); //The default Thread size. When it overflows, it queues up to the size of Queue Capacity
executor.setQueueCapacity(1); //The size of the waiting queue. Increase Thread to MaxPoolSize when overflowing
executor.setMaxPoolSize(500); //Setting how much Thread to increase. If it overflows from this value, the process will be rejected and an Exception will occur.
executor.setThreadNamePrefix("Thread2--");
executor.initialize();
return executor;
}
@Bean("Reject") //With this setting, queuing cannot be performed, Thread cannot be increased, and a RejectedExecutionException occurs.
public Executor rejectTaskExecuter() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(1);
executor.setQueueCapacity(0);
executor.setMaxPoolSize(1);
executor.setThreadNamePrefix("Reject--");
executor.initialize();
return executor;
}
}
When you execute the process, the following log appears and you can see that it is running asynchronously
2018-11-27 20:19:13.181 WARN 8711 --- [nio-8080-exec-5] c.e.asynctraining.FindNameContoller : request started
2018-11-27 20:19:13.181 WARN 8711 --- [TaskExecutor-31] com.example.asynctraining.AsyncService : Async function started. processName: heavysleepTime: 3000
2018-11-27 20:19:13.182 WARN 8711 --- [TaskExecutor-32] com.example.asynctraining.AsyncService : Async function started. processName: lightsleepTime: 1000
2018-11-27 20:19:14.187 WARN 8711 --- [onPool-worker-2] c.e.asynctraining.FindNameContoller : finished name=light, sleep = 1000
2018-11-27 20:19:16.182 WARN 8711 --- [onPool-worker-2] c.e.asynctraining.FindNameContoller : finished name=heavy, sleep = 3000
2018-11-27 20:19:16.194 WARN 8711 --- [nio-8080-exec-5] c.e.asynctraining.FindNameContoller : request finished. time: 3013ms
Recommended Posts