컨트롤러의 Spring Boot @Async 메서드가 동시에 실행되고 있습니다.
Boot [basic]Spring Boot을 통해 .jQuery.get()"요청이 큐잉되었습니다" 등의 응답을 즉시 수신해야 합니다.이를 위해 컨트롤러를 작성했습니다.
@Controller
public class DoSomeWorkController {
@Autowired
private final DoWorkService workService;
@RequestMapping("/doSomeWork")
@ResponseBody
public String doSomeWork() {
workService.doWork(); // time consuming operation
return "Your request has been queued.";
}
}
DoWorkServiceImpl을 DoWorkService매우 심플합니다.시간이 많이 걸리는 작업을 수행할 수 있는 단일 방법이 있습니다.이 서비스 콜에서 반환되는 것은 필요하지 않습니다.실패 시나 성공 시나리오는 작업 종료 시 이메일이 발송되기 때문입니다. 사실상 '아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아아,아,아,아.
@Service
public class DoWorkServiceImpl implements DoWorkService {
@Async("workExecutor")
@Override
public void doWork() {
try {
Thread.sleep(10 * 1000);
System.out.println("completed work, sent email");
}
catch (InterruptedException ie) {
System.err.println(ie.getMessage());
}
}
}
이게 될 줄 알았는데 브라우저의 Ajax 요청이 10초 동안 기다린 후 응답을 반환했습니다. 맵 하고 있습니다.@Async★★★★★★★★★★★★★★▼기존의 Spring 어플리케이션에서는 일반적으로 XML 설정에 다음과 같이 추가합니다.
<task:annotation-driven />
<task:executor id="workExecutor" pool-size="1" queue-capacity="0" rejection-policy="DISCARD" />
그래서 메인 어플리케이션클래스에 이와 동등한 것을 쓰는 것이 도움이 된다고 생각했습니다.
@SpringBootApplication
@EnableAsync
public class Application {
@Value("${pool.size:1}")
private int poolSize;;
@Value("${queue.capacity:0}")
private int queueCapacity;
@Bean(name="workExecutor")
public TaskExecutor taskExecutor() {
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
taskExecutor.setMaxPoolSize(poolSize);
taskExecutor.setQueueCapacity(queueCapacity);
taskExecutor.afterPropertiesSet();
return taskExecutor;
}
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
이것으로 동작은 변경되지 않았습니다.Ajax 응답은 요청 전송 후 10초 후에도 계속 도착합니다.제가 무엇을 빠뜨리고 있나요?
Spring Boot 어플리케이션은 여기에서 다운로드할 수 있습니다.Maven이 설치되어 있으면 다음 간단한 명령으로 프로젝트를 실행할 수 있습니다.
mvn clean spring-boot:run
주의: 이 문제는 아래의 @Dave Syer에 의한 답변으로 해결되었습니다.이 답변은 제가 부재중임을 지적한 것입니다.@EnableAsync위의 코드 스니펫에 라인이 있었는데도 내 어플리케이션에서.
요.@Async같은 클래스의 다른 메서드에서 메서드를 사용합니다.AspectJ 를 AspectJ로 한@EnableAsync(물론 직조기도 제공하지만) 작동하지 않습니다(구글의 "자체 기동").은 '이렇게'를 입니다.@Async 방법@Bean.
아직 @Asnyc의 모든 단계를 찾고 계신 분들을 위해 다음과 같은 답변을 드립니다.
다음은 @Async의 간단한 예입니다.Spring Boot 어플리케이션에서 @Async를 동작시키는 순서는 다음과 같습니다.
스텝 1: @EnableAsync 주석을 추가하고 응용 프로그램클래스에 TaskExecutor Bean을 추가합니다.
예:
@SpringBootApplication
@EnableAsync
public class AsynchronousSpringBootApplication {
private static final Logger logger = LoggerFactory.getLogger(AsynchronousSpringBootApplication.class);
@Bean(name="processExecutor")
public TaskExecutor workExecutor() {
ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
threadPoolTaskExecutor.setThreadNamePrefix("Async-");
threadPoolTaskExecutor.setCorePoolSize(3);
threadPoolTaskExecutor.setMaxPoolSize(3);
threadPoolTaskExecutor.setQueueCapacity(600);
threadPoolTaskExecutor.afterPropertiesSet();
logger.info("ThreadPoolTaskExecutor set");
return threadPoolTaskExecutor;
}
public static void main(String[] args) throws Exception {
SpringApplication.run(AsynchronousSpringBootApplication.class,args);
}
}
스텝 2: 비동기 프로세스를 실행하는 메서드 추가
@Service
public class ProcessServiceImpl implements ProcessService {
private static final Logger logger = LoggerFactory.getLogger(ProcessServiceImpl.class);
@Async("processExecutor")
@Override
public void process() {
logger.info("Received request to process in ProcessServiceImpl.process()");
try {
Thread.sleep(15 * 1000);
logger.info("Processing complete");
}
catch (InterruptedException ie) {
logger.error("Error in ProcessServiceImpl.process(): {}", ie.getMessage());
}
}
}
스텝 3: 컨트롤러에 API를 추가하여 비동기 처리를 실행합니다.
@Autowired
private ProcessService processService;
@RequestMapping(value = "ping/async", method = RequestMethod.GET)
public ResponseEntity<Map<String, String>> async() {
processService.process();
Map<String, String> response = new HashMap<>();
response.put("message", "Request is under process");
return new ResponseEntity<>(response, HttpStatus.OK);
}
GitHub에 블로그와 어플리케이션도 작성했습니다.http://softwaredevelopercentral.blogspot.com/2017/07/asynchronous-processing-async-in-spring.html 를 확인해 주세요.
비슷한 문제가 있어서 올바른 콩에 @Async와 @EnableAsync라는 주석을 넣었는데도 메서드는 동기적으로 실행되고 있었습니다.로그를 확인한 후 ThreadPoolTask 유형의 빈이 두 개 이상 있다는 경고가 표시되었습니다.실행자와 작업 호출된 실행자가 없습니다.실행자 So...
@Bean(name="taskExecutor")
public ThreadPoolTaskExecutor defaultTaskExecutor() {
ThreadPoolTaskExecutor pool = new ThreadPoolTaskExecutor();
//Thread pool configuration
//...
return pool;
}
스레드 풀에서 사용할 수 있는 설정에 대해서는, http://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/scheduling/concurrent/ThreadPoolTaskExecutor.html 를 참조해 주세요.
다음의 3개의 순서에 따릅니다.
1단계 : @configuration 또는 @SpringBoot Application과 함께 @EnableAsync를 사용합니다.
@EnableAsync 퍼블릭클래스 애플리케이션 {
2 순서:
/**
* THIS FOR ASYNCRONOUS PROCESS/METHOD
* @return
*/
@Bean
public Executor asyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(5);
executor.setQueueCapacity(500);
executor.setThreadNamePrefix("Asynchronous Process-");
executor.initialize();
return executor;
}
3단계 : 원하는 방법 위에 @Async를 놓습니다.
T
@dave-syer 응답 코드샘플:
이것은 비동기적으로 동작합니다.
private void longRunning() {
try {
log.info("wait 3 seconds");
Thread.sleep(3000);
} catch (InterruptedException e1) {
}
log.info("done");
}
@Async
@Override
public void doWork() {
longRunning();
}
하지만 이것은 아닙니다.
@Async
private void longRunning() {
try {
log.info("wait 3 seconds");
Thread.sleep(3000);
} catch (InterruptedException e1) {
}
log.info("done");
}
@Override
public void doWork() {
longRunning();
}
spring-boot 메인클래스를 사용하여 비동기 설정을 정의했습니다.그@EnableAsync주석은 스프링의 실행 기능을 가능하게 합니다.@Async백그라운드 스레드 풀의 메서드.또한 이 클래스는 새 빈을 정의하여 실행자를 사용자 정의합니다.여기서 메서드는taskExecutor()Spring에 의해 검색된 특정 메서드명이기 때문입니다.
Spring-Boot-Application.class
@SpringBootApplication
@EnableAsync
public class AsyncApplication {
@Value("${config.threadpool.corepool.size}")
private Integer corePoolSize;
@Value("${config.threadpool.maxpool.size}")
private Integer maxPoolSize;
public static void main(String[] args) {
SpringApplication.run(AsyncApplication.class, args);
}
//name of below method should not be changed.
@Bean
public Executor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(corePoolSize);
executor.setMaxPoolSize(maxPoolSize);
//other proeprties to be set here
executor.setThreadNamePrefix("ASYNC-");
executor.initialize();
return executor;
}
}
구현에서 사용@Async메서드 수준에서 메서드를 비동기화합니다.메서드를 사용하려면 공개해야 합니다.@Async.또한.@Async주석 메서드 호출@Async메서드는 동작하지 않습니다.
아래를 참조하기 위한 구현 예시 -
@Async
public void updateData(String userId) throws ApplicationException {
logger.info("Updating details for User with {}", userId);
//your code goes here...
}
설정 속성은 에 정의되어 있습니다.application.properties파일
#Core Pool Size for Async
config.threadpool.corepool.size=100
#Max Pool Size for Async
config.threadpool.maxpool.size=400
풀의 정의 방법에 관한 규칙에 대해서는, 「Rules-of-a-threadpool executor
언급URL : https://stackoverflow.com/questions/29284008/spring-boot-async-method-in-controller-is-executing-synchronously
'programing' 카테고리의 다른 글
| 각도 $q 약속이 해결되었는지 확인하는 방법 (0) | 2023.03.31 |
|---|---|
| Android Client에서 서버로 GZIP 압축 JSON을 전송할 때 사용해야 하는 헤더는 무엇입니까? (0) | 2023.03.31 |
| Travis/Jest:TypeError: 개체 '#'의 읽기 전용 속성 'Symbol(Symbol.toStringTag)'에 할당할 수 없습니다. (0) | 2023.03.31 |
| 모나코 에디터 동적 크기 조정 가능 (0) | 2023.03.31 |
| 여러 요소에서 ng 클릭으로 클래스 전환 (0) | 2023.03.31 |