java 在Sping Boot 中快速处理两个大API数据处理

lawou6xi  于 2023-06-04  发布在  Java
关注(0)|答案(2)|浏览(105)

我正在开发Sping Boot 应用程序,其中创建了一些要从另一个API处理的数据和报告。
我有这样的情况,我必须从一个API中获取数据并处理它,从第一个API中提取一些数据,然后调用第二个API来设置对象中的结果。
这是连续的事情,我必须从第一个然后从第一个的结果第二个API命中获得数据。

public MyOrderPart getReport(**List<FirstAPIResult> serviceOptions**) {

        MyOrderPart myOrderPart = new MyOrderPart();
        List<MyOrderPartObject> myOrderPartList = new LinkedList<>();      
        try {          
            HttpHeaders headers = new HttpHeaders();
            headers.set(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE);
            headers.set(HttpHeaders.AUTHORIZATION, token);
            HttpEntity<?> entity = new HttpEntity<>(headers);
            HashMap hashMap = new HashMap();
            if (!serviceOptions.isEmpty()) {
                for (MyReportModel myReportModel : serviceOptions) {
                    List<SomePartHeader> partHeaderList = myReportModel.getPartHeaders();
                    for (SomePartHeader partHeader : partHeaderList) {
                        MyOrderPartObject myOrderPartObject = new MyOrderPartObject();
                        myOrderPartObject.setSegmentNo(String.valueOf(myReportModel.getSegmentNo()));
                        myOrderPartObject.setOperationNo(String.valueOf(myReportModel.getOperationNo()));
                        myOrderPartObject.setCompCode(myReportModel.getSmcs().getCompCode());
                        myOrderPartObject.setJobCode(myReportModel.getSmcs().getJobCode());
                        myOrderPartObject.setModCode(myReportModel.getSmcs().getModCode());
                        myOrderPartObject.setDescription(myReportModel.getDescription().getDescription());
                        myOrderPartObject.setPartBeginSn(String.valueOf(partHeader.getPartHeaderBeginSn()));
                        myOrderPartObject.setPartEndSn(String.valueOf(partHeader.getPartHeaderEndSn()));
                        myOrderPartObject.setPartGroupNumber(partHeader.getPartHeaderGroupNumber().trim());
                        Optional<SomeJobPart> jobPart = partHeader.getJobParts()
                                .stream()
                                .filter(x -> partHeader.getPartHeaderGroupNumber()
                                        .trim()
                                        .equals(x.getMasterPart().getPartNumber().trim()))
                                .findAny();
                        if (jobPart.isPresent()) {
                            //Second API
                             String description = getDescriptionFromSecondAPI(jobPart.get().getPartGroupNumber(), entity);
                            myOrderPartObject.setPartDescription(description);
 hashMap.put(jobPart.get().getPartGroupNumber(), workOrderPartObject);
                        } else {
                            myOrderPartObject.setPartDescription("");
                        }                      
                        myOrderPartList.add(myOrderPartObject);

                    }
                }               
            }
        } catch (Exception ex) {
            context.getLogger().info("error: " + ex.getMessage());
        }
        myOrderPart.setWorkOrderPart(myOrderPartList);      
        return myOrderPart;
    }

这里列出serviceOptions是One API返回的,我正在处理。
现在必须从第一个进程调用getDescriptionFromSecondAPI(...)

public String getDescriptionFromSecondAPI(String partNumber, HttpEntity<?> entity) {

    String secondURL = SECOND_API_BASE_URL + "?q=" + partNumber + "&sId=constant";
    RestTemplate restTemplate = new RestTemplate();
    ResponseEntity<Object> respEntity = null;
    String description = "";
    try {
        respEntity = restTemplate.exchange(secondURL , HttpMethod.GET, entity,
                Object.class
        );
        Object body = respEntity.getBody();
        String name = (String) ((LinkedHashMap) ((ArrayList) ((LinkedHashMap) body).get("abc")).get(0)).get("name");
        if (name != null) {
            description = name.substring(name.indexOf(":") + 1, name.length());
        }

    } catch (Exception ex) {
        context.getLogger().info("Exception  : " + ex);
    }
    return description.trim();
}

getDescriptionFromSecondAPI(...)这个方法需要很长时间才能得到结果,而setPartDescription(here),它只需要不到一秒钟就可以得到一个partNumber的数据。
如何提高方法的性能,以便快速获得响应并设置它。输入依赖于第一API。我怎么能改善它。
我也试过这个:
hashMap是在获取jobPart时在if条件下创建的,然后在处理它之后:

ExecutorService executorService = Executors.newFixedThreadPool(100);
            executorService.execute(() -> {
                hashMap.forEach((key, value) ->
                {
                    String description = getDescriptionFromSecondAPI(key.toString(), entity);
                    ((MyOrderPartObject) value).setPartDescription(description);
                });
            });

然后也需要大约4+分钟的时间来设置完整的对象。如何提高java spring Boot 的性能

5w9g7ksd

5w9g7ksd1#

如果第二个API不允许您请求多个部件描述,那么这里就没有什么可做的了,因为您仍然需要分别请求每个部件。
您可以尝试查看是否获得任何性能改进的一件事是使用池连接管理器,而不是每次都在getDescriptionFromSecondAPI()中创建新的RestTemplate。你说你正在使用Sping Boot ,所以你可以尝试在你的配置类中定义以下bean(摘自here的片段,你可能需要稍微修改一下以适应你的目的,我不知道你在你的项目中有什么依赖关系):

@Bean
public RestTemplate pooledRestTemplate() {
    PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
    connectionManager.setMaxTotal(2000);
    connectionManager.setDefaultMaxPerRoute(2000);

    HttpClient httpClient = HttpClientBuilder.create()
        .setConnectionManager(connectionManager)
        .build();

    return new RestTemplateBuilder().rootUri("http://service-b-base-url:8080/")
        .setConnectTimeout(Duration.ofMillis(1000))
        .setReadTimeout(Duration.ofMillis(1000))
        .messageConverters(new StringHttpMessageConverter(), new MappingJackson2HttpMessageConverter())
        .requestFactory(() -> new HttpComponentsClientHttpRequestFactory(httpClient))
        .build();
}

将该RestTemplate注入到有问题的服务中,看看是否有帮助。:)

unftdfkk

unftdfkk2#

您当前对executor服务的使用似乎只是简单地使用一个单独的线程来按顺序运行所有请求(除非我真的错过了hashMap.forEach的一些隐藏特性)。您可能希望并行执行它们。这意味着你的map需要在executor调用之外创建,你需要将每个检索单独提交给executor,而不是在一个单独的runnable中完成它们。
比如:

hashMap.forEach((key, value) ->
     executorService.execute(() -> {
            {
                String description = getDescriptionFromSecondAPI(key.toString(), entity);
                ((MyOrderPartObject) value).setPartDescription(description);
            };
        }));

(code可能在语法上不正确,但应该给予你的想法;注意你的结构需要是线程安全的…)

相关问题