简体   繁体   English

CompletableFuture 不调用其他 Bean 中的 static 方法

[英]CompletableFuture not calling static methods in other Beans

This is one of my first posts, please forgive me if it is not formatted properly or giving the correct information, but I have been searching for the answer for days and still cannot figure it out.这是我的第一篇文章,如果格式不正确或提供的信息不正确,请原谅我,但我已经搜索了好几天的答案,但仍然无法弄清楚。

I have a test where I am using Spring to inject beans.我有一个测试,我正在使用 Spring 注入 bean。 I need to run multiple API calls simultaneously, so I used CompletableFuture to do it.我需要同时运行多个 API 调用,所以我使用 CompletableFuture 来完成它。 But when I do that, it seems that all static methods in a Utility class that are called in other components don't get called at all.但是当我这样做时,似乎在其他组件中调用的 Utility class 中的所有 static 方法都没有被调用。 The thread just stops and no error messages or anything, but using logging, I traced it to when the static method is being called.线程刚刚停止并且没有错误消息或任何东西,但是使用日志记录,我将其跟踪到调用 static 方法的时间。

I see that in all the beans, everything is being injected properly, but just when it his that static method, it just stops.我看到在所有 bean 中,一切都被正确注入,但就在他的 static 方法时,它就停止了。 If I test without CompletableFuture, it works just fine.如果我在没有 CompletableFuture 的情况下进行测试,它就可以正常工作。 I have been spending days trying to figure this out and I just can't find a good way to seemingly test the code using unit testing.我花了好几天时间试图解决这个问题,但我就是找不到使用单元测试看似测试代码的好方法。

I have a thread that calls a service bean that is injected with properties which works fine, then it calls another service bean "JobService"我有一个调用服务 bean 的线程,该服务 bean 注入了工作正常的属性,然后它调用另一个服务 bean“JobService”

Test class:测试class:

@EnableAsync
class BillingRevenueVsExpensesServiceTest {
    private final Logger LOGGER = LogManager.getLogger(this.getClass().getName());

    @Test
    public void getBillingRevenueVsExpenses() {
        LOGGER.info("1 Starting Thread");
        ApplicationContext billingRevenueVsExpensesServiceThreadContext = new AnnotationConfigApplicationContext(billingRevenueVsExpensesDataServiceThreadConfig.class);
        ApplicationContext topLevelOwnerDataServiceThreadContext = new AnnotationConfigApplicationContext(TopLevelOwnerDataServiceThreadConfig.class);

        BillingRevenueVsExpensesDataServiceThread billingRevenueVsExpensesDataServiceThread = billingRevenueVsExpensesServiceThreadContext.getBean(BillingRevenueVsExpensesDataServiceThread.class);
        TopLevelOwnerDataServiceThread topLevelOwnerDataServiceThread = topLevelOwnerDataServiceThreadContext.getBean(TopLevelOwnerDataServiceThread.class);
        try {
            CompletableFuture<String> billingRevenueVsExpensesDataServiceThreadCompletableFutureJsonString = billingRevenueVsExpensesDataServiceThread.getData();
            CompletableFuture<String> topLevelOwnerDataServiceThreadCompletableFutureJsonString = topLevelOwnerDataServiceThread.getData();
        } catch (Exception e) {
            LOGGER.error(e);
            throw new RuntimeException(e);
        }
    }
}
@Service("jobService")
public class JobService {

    private final Logger LOGGER = LogManager.getLogger(this.getClass().getName());

    int spacesToIndentEachLevel = 2;

    //Injected Fields
    private final String baseURL;
    private final String portfolioID;
    private final String portfolioType;
....
    public String getJobID(String viewName, String viewID,  String timePeriod) {
        LOGGER.info("7 Starting job name: " + viewName + " view ID: " + viewID);
// CALLS BELOW METHOD IN THE SAME CLASS
        String[] timePeriodList = timePeriodCreator(timePeriod);
        //DOES NOT CONTINUE IN THE ABOVE

....
    private String[] timePeriodCreator (String timePeriod) {
        String[] timePeriodList = new String[2];
        Date date = new Date();
        LOGGER.info("Todays Date: " + date);

        switch (timePeriod) {
            case "previousEndOfMonthCurrentEndOfMonth" -> {
                LOGGER.debug("In the timeperiod utlity");
                timePeriodList[0] = DateUtilities.getPreviousYearMonthDate(date);
                timePeriodList[1] = DateUtilities.getEndCurrentYearMonthDate(date);
                LOGGER.debug("9 Timeperiod produced: " + timePeriodList[0] + " to " + timePeriodList[1]);
....

        return timePeriodList;
    }

Here is my Date Utilities class:这是我的日期实用程序 class:

public final class DateUtilities {

    private static final Logger LOGGER = LogManager.getLogger(DateUtilities.class.getName());

    final static DateFormat yearMonthDateFormat = new SimpleDateFormat("yyyy-MM-dd");

    // Gets the previous months end date
    public static String getPreviousYearMonthDate(Date date) {
        LOGGER.info("Getting Previous Month Date");
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.add(Calendar.MONTH, -1);
        cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH));
        Date previousYearMonthDate = cal.getTime();
        return yearMonthDateFormat.format(previousYearMonthDate);
    }
....
}

ConsoleOutput控制台输出

15:24:29.847 [poolThread-1] INFO com.operations.backend.services.JobService - 7 Starting job name: billingRevenueVsExpensesView view ID: 386839
15:24:29.847 [poolThread-1] INFO com.operations.backend.services.JobService - 7 Starting job name: topLevelOwnerView view ID: 392697
15:24:29.847 [poolThread-1] INFO com.operations.backend.services.JobService - 8 Generating job for view ID: 386839
15:24:29.847 [poolThread-1] INFO com.operations.backend.services.JobService - 8 Generating job for view ID: 392697
15:24:29.847 [poolThread-1] INFO com.operations.backend.services.JobService - Todays Date: Fri Jan 13 15:24:29 EST 2023
15:24:29.847 [poolThread-1] DEBUG com.operations.backend.services.JobService - In the timeperiod utlity
15:24:29.847 [poolThread-1] INFO com.operations.backend.services.JobService - Todays Date: Fri Jan 13 15:24:29 EST 2023
15:24:29.847 [poolThread-1] DEBUG com.operations.backend.services.JobService - In the timeperiod utlity
Process finished with exit code 0

It basically stops when its calling the static date method.它在调用 static 日期方法时基本上停止了。 If I just do a regular call as opposed to the CompletableFuture, it works fine.如果我只是做一个常规调用而不是 CompletableFuture,它工作正常。 I changed some names around for the sake of posting.为了发布,我更改了一些名称。

EDIT: Here is my Thread Class that has the get data:编辑:这是我的线程 Class,它具有获取数据:

@Service("billingRevenueVsExpensesDataServiceThread")
public class BillingRevenueVsExpensesDataServiceThread extends AddeparJobsAPICallService {

...

    public BillingRevenueVsExpensesDataServiceThread(String viewName, String viewID, String timePeriod) {
        LOGGER.info("3 Thread Setting Thread Parameters: " + viewName + " " + viewID);
        this.viewName = viewName;
        this.viewID = viewID;
        this.timePeriod = timePeriod;
    }

    @Async
    public CompletableFuture<String> getData() {
        try {
            LOGGER.info("4 Starting Addepar Jobs API Call Service: " + viewName + " " + viewID);
            jsonStringOutput = runJob(viewName, viewID, timePeriod);
            return CompletableFuture.completedFuture(jsonStringOutput);
        } catch (Exception e) {
            LOGGER.error(e);
            return CompletableFuture.completedFuture("ERROR");
        }
    }

Here is the AddeparCallService这是 AddeparCallService

@ContextConfiguration(classes = {JobServiceConfig.class})
public class AddeparJobsAPICallService {




    public String runJob(String viewName, String viewID, String timePeriod) {
        LOGGER.info("5 Running Addepar API Jobs Call Service: " + viewName);
        ApplicationContext jobServiceContext = new AnnotationConfigApplicationContext(JobServiceConfig.class);
        JobService jobService = jobServiceContext.getBean(JobService.class);

//        LOGGER.info("Generating view: " + viewName + " job ID for: " + viewID + " for timeperiod:" + timePeriod);
        String jobID = jobService.getJobID(viewName, viewID, timePeriod);
        LOGGER.info("Generated Job ID: " + jobID + " for view: " + viewName + " job ID for: " + viewID + " for timeperiod:" + timePeriod);
        try {
            LOGGER.info("Waiting for job generation 10 minutes");
            Thread.sleep(600000);
            //Puts the json output into the key: billingRevenueVsExpenses
            return jobService.getJobResults(jobID, viewName);
        } catch (Exception e) {
            LOGGER.error("Issue with: " + AddeparJobsAPICallService.class.getName() + " : " + e);
            return "Loading";
        }
    }

}

Try to replace those 2 lines尝试替换这两行

CompletableFuture<String> billingRevenueVsExpensesDataServiceThreadCompletableFutureJsonString = billingRevenueVsExpensesDataServiceThread.getData();
CompletableFuture<String> topLevelOwnerDataServiceThreadCompletableFutureJsonString = topLevelOwnerDataServiceThread.getData();

With

billingRevenueVsExpensesDataServiceThread.getData().get();
CompletableFuture<String> topLevelOwnerDataServiceThread.getData().get();

Looks like CompletableFutures created, but not executed.看起来 CompletableFutures 已创建,但未执行。

Ok, so I think I got it.好的,所以我想我明白了。 I went through each class and made sure I had the minimal annotations.我检查了每个 class 并确保我有最少的注释。 I removed all of them and then added each of them testing to make sure it worked.我删除了所有这些,然后添加了每个测试以确保它有效。 And since I am trying to run everything in parallel.而且因为我正在尝试并行运行所有内容。 It looks like in order to use Completeable.allOf, I just converted the getData functions into a String return as opposed to a CompletableFuture and removed the @Async annotation:看起来为了使用 Completeable.allOf,我只是将 getData 函数转换为 String 返回而不是 CompletableFuture,并删除了 @Async 注释:

    public TopLevelOwnerDataServiceThread(String viewName, String viewID, String timePeriod) {
    LOGGER.info("3 Setting Thread Parameters: " + viewName + " " + viewID);
    this.viewName = viewName;
    this.viewID = viewID;
    this.timePeriod = timePeriod;
}

I followed this to get the rest working and it is working in parallel now.我按照这个让 rest 工作,它现在正在并行工作。 Thank you all for the help!谢谢大家的帮助!

https://dzone.com/articles/java-8-parallel-processing-with-completable-future https://dzone.com/articles/java-8-parallel-processing-with-completable-future

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM