Асинхронность связана с проблемой переключения контекста. Например, объект запроса Spring фактически существует в объекте контекста, и мы можем получить его, при условии, что вся ваша логика выполнения является потоком.ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
Именно для того, чтобы получить контекст, он бы перехватил его в моей логике и ввел.
Но иногда задействованы асинхронные контексты.
@Slf4j
@Service
public class UserService {
@Async
public void find() {
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (requestAttributes == null) {
log.info("当前线程为 {} 位置为{} require对象为空.", Thread.currentThread().getName(), "service");
} else {
HttpServletRequest request = requestAttributes.getRequest();
log.info("当前线程为 {},请求方法为 {},请求路径为:{} 位置为:{}", Thread.currentThread().getName(), request.getMethod(), request.getRequestURL(), "service");
}
}
}
Включить асинхронность, основная программа.
@Slf4j
@EnableAsync
@RestController
@SpringBootApplication
public class SpringAsyncApplication {
private final UserService service;
@Autowired
public SpringAsyncApplication(UserService service) {
this.service = service;
}
public static void main(String[] args) {
SpringApplication.run(SpringAsyncApplication.class, args);
}
@GetMapping("/find/{id}")
public String echo(@PathVariable(value = "id") String id) {
service.find();
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = requestAttributes.getRequest();
log.info("当前线程为 {} 请求方法为 {} 请求路径为{} 位置为{}", Thread.currentThread().getName(), request.getMethod(), request.getRequestURL(),"controller");
return id;
}
}
мы нашли журналы
2020-03-30 17:09:14.475 INFO 16720 --- [nio-8080-exec-1] c.e.springasync.SpringAsyncApplication : 当前线程为 http-nio-8080-exec-1 请求方法为 GET 请求路径为http://localhost:8080/find/111 位置为controller
2020-03-30 17:09:14.480 INFO 16720 --- [cTaskExecutor-1] c.e.springasync.service.UserService : 当前线程为 SimpleAsyncTaskExecutor-1 位置为service require对象为空.
Таким образом, в настоящее время контекст не существует, поэтому нам нужно настроить его вручную, Spring предоставляет хороший рабочий объект.
@Configuration
public class Config {
private static final String ASYNC_EXECUTOR_NAME = "asyncExecutor";
@Bean(name = ASYNC_EXECUTOR_NAME)
public Executor executor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setThreadNamePrefix(ASYNC_EXECUTOR_NAME);
executor.setCorePoolSize(5);
executor.setMaxPoolSize(5);
executor.setQueueCapacity(-1);
// 这里在每次异步调用的时候, 会包装一下.
executor.setTaskDecorator(runnable -> {
// 这个时候还是同步状态
RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
// 返回的这个 runnable对象 才是去调用线程池.
return () -> {
try {
// 我们set 进去 ,其实是一个ThreadLocal维护的.
RequestContextHolder.setRequestAttributes(requestAttributes);
runnable.run();
} finally {
// 最后记得释放内存
RequestContextHolder.resetRequestAttributes();
}
};
});
return executor;
}
}
Итак, в это время
2020-03-30 17:10:48.377 INFO 18060 --- [nio-8080-exec-2] c.e.springasync.SpringAsyncApplication : 当前线程为 http-nio-8080-exec-2 请求方法为 GET 请求路径为http://localhost:8080/find/111 位置为controller
2020-03-30 17:10:48.382 INFO 18060 --- [ asyncExecutor1] c.e.springasync.service.UserService : 当前线程为 asyncExecutor1,请求方法为 GET,请求路径为:http://localhost:8080/find/111 位置为:service
Это решение.