【问题标题】:Asynchronous Controller in Spring BootSpring Boot 中的异步控制器
【发布时间】:2019-09-27 04:51:06
【问题描述】:

我使用 Spring Boot 创建了 Web 服务,其中有一个休息控制器,它通过基于供应商的 JDBC 驱动程序访问数据库并获取记录。在此过程中检索的记录数超过 80K 记录。因此,当我们以 client 的身份访问 rest 端点时,我们会遇到超时错误。

我已尝试使用以下教程设置异步调用。但不幸的是,其余调用仍然超时。

https://howtodoinjava.com/spring-boot2/enableasync-async-controller/

控制器

    @RequestMapping(value = "/v1/lr/fullpositionasync", produces = {APPLICATION_JSON_UTF8_VALUE},   method = RequestMethod.GET)
    @ResponseBody
    public CompletableFuture<List<Position>> retrieveTradePositionsFullAsync(HttpServletRequest request, HttpServletResponse response) throws ExecutionException, InterruptedException {

        CompletableFuture<List<Position>> positionList =null;
        try {
            positionList = positionService.getFullPosition();
        }
        catch(Exception e){
            log.info("Error Occurred in Controller is:"+e.getMessage());
        }
        CompletableFuture.allOf(positionList).join();
        log.info(String.valueOf(positionList.get()));
        return positionList;
    }

服务

@Service
@Slf4j
public class PositionServiceImpl implements PositionService {

    @Autowired
    private PositionDao positionDao;

    @Async("asyncExecutor")
    @Override
    public CompletableFuture<List<Position>> getFullPosition()  {

        List<Position> fullpositionList = null;
        log.info("Getting the full Position process started");
        fullpositionList = positionDao.retrieveData();
        log.info("Total Positions retrieved:"+fullpositionList.size());
        try {
            log.info("Thread is about to sleep 1000 milliseconds");
            Thread.sleep(1000);
        }catch(InterruptedException e){
            log.info(e.getMessage());
        }
        log.info("Full Positions retrieval completed");
        return CompletableFuture.completedFuture(fullpositionList);
    }


}

配置

@Configuration
@EnableAsync
@Slf4j
public class AsyncConfiguration
{
    @Bean(name = "asyncExecutor")
    public Executor asyncExecutor()
    {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(20);
        executor.setMaxPoolSize(1000);
        executor.setWaitForTasksToCompleteOnShutdown(true);
        executor.setThreadNamePrefix("AsynchThreadForEndPoint-");
        executor.initialize();
        log.info("Executor is :"+executor.toString());
        return executor;
    }
}

@Repository
public class PositionDaoImpl implements PositionDao {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    private static final String ALL_POSITION_QUERY = "call AllPositionProcedure()";


    public List<Position> retrieveData() {
        return jdbcTemplate.query(ALL_POSITION_QUERY, new BeanPropertyRowMapper(Position.class));
        //  List<Map<String, Object>> mapList = jdbcTemplate.queryForList(sql);

    }

【问题讨论】:

  • 嗨!请问你想用这些记录做什么?那么你返回 80K 记录,它们是如何使用的呢?在 UI 中显示?还是出口?返回 80K 记录的目的是什么?
  • 我正在尝试创建 JSON 输出,因为另一个 Web 服务正在尝试访问我们的服务以获取数据。这是一天加载的开始。
  • 您能否使用分块响应和分页浏览 JDBC 结果,在处理完每个页面后将其发送回客户端?
  • 但是执行数据库查询的 JDBC 供应商驱动程序返回单个数据块,而不是通过结果分页

标签: rest spring-boot asynchronous


【解决方案1】:

您不能使用 JDBC 对数据库执行异步操作。 JDBC 是阻塞的,所以它会阻塞你的线程,直到操作被执行。如果您想以异步方式执行操作,请使用R2DBC 而不是 JDBC。

【讨论】:

  • 不幸的是,我们可以通过基于供应商的 JDBC 驱动程序连接到数据库的唯一方法。我们不能使用任何其他驱动程序。
  • 那么你应该避免在阻塞的数据库连接上使用 Async 和 CompletableFuture。使用它你不会收到任何性能。
  • 那么我怎样才能在这个服务上设置异步休息调用呢?
【解决方案2】:

对于您的用例,最好的方法是将您的应用程序转换为 Reactive Streams (Flux)。

Flux 是响应式流发布器。它是 JVM 的完全非阻塞反应式编程基础,具有高效的需求管理(以管理“背压”的形式)。它直接与 Java 8 功能 API 集成,特别是 CompletableFuture、Stream 和 Duration。它提供可组合的异步序列 API Flux(用于 [N] 个元素)和 Mono(用于 [0|1] 个元素),广泛实现了Reactive Streams 规范。

在现有应用中实现非常简单。只需更改您的存储库返回类型 Flux 而不是 List 或 Future。

更多信息可以参考Here

【讨论】:

  • ReactiveStreams 在响应式数据源上运行良好。如果你会阻塞你的线程,你将不会获得任何性能。他已经声明他的数据源被阻塞了。
  • 您可以使用 David Moten 的 rxjava2-jdbc 库。它需要一个普通的 JDBC 驱动程序,并允许您以不会阻塞您的应用程序的方式与之交互。它通过在不同线程上调度潜在的阻塞工作来做到这一点。此外,它具有 DSL,可让您将 SQL 语句和结果建模为流。这使得集成到您的反应式应用程序中变得轻而易举。
  • ReactiveStreams 也适用于 JDBC,您也可以使用它。
  • 好的,谢谢。你能给我一些如何使用反应流的例子吗?另外我只有restful webservice但没有UI ..在这种情况下我还能使用react流吗?
猜你喜欢
  • 2020-11-13
  • 1970-01-01
  • 1970-01-01
  • 2016-09-17
  • 2019-10-09
  • 2021-04-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多