当前位置: 首页 > 知识库问答 >
问题:

无法捕获Spring中异步方法引发的异常

朱越
2023-03-14

我无法在Spring中捕获异步方法抛出的异常。我已经编写了一个未捕获的异常处理程序来捕获,但没有成功。该应用程序将启用启动任意数量的永远运行的异步作业。我认为我的异步方法需要返回Future,以便我可以将其存储在hashmap中并检查其状态或停止作业。我也可以通过存储它来获取所有正在运行的作业。我认为我不能使用get method of Future,因为如果输入正确,它会阻塞,我的作业将永远运行。如果输入正常,我需要发送状态为开始。每当Async方法中发生异常时,它就会被抛出,但我无法捕获它。我该怎么做?这是我的完整代码。

一个pplication.java

@SpringBootApplication
@EnableAsync
public class Application  {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

AsyncConfig。Java语言

@EnableAsync
@Configuration
public class AsyncConfig implements AsyncConfigurer {

    @Override
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(5);
        executor.setMaxPoolSize(5);
        executor.setQueueCapacity(100);
        executor.setThreadNamePrefix("MyExecutor-");
        executor.initialize();
        return executor;
    }


    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return new AsyncExceptionHandler();
    }
}

AsyncExceptionHandler.java

public class AsyncExceptionHandler implements AsyncUncaughtExceptionHandler {
    @Override
    public void handleUncaughtException(Throwable throwable, Method method, Object... obj) {

        System.out.println("Exception Cause - " + throwable.getMessage());
        System.out.println("Method name - " + method.getName());
        for (Object param : obj) {
            System.out.println("Parameter value - " + param);
        }
    }
}

创建Bucket。Java语言

@Service
public class createBucket {
    @Async
    public Future<String> start(String config){
        try {
            JSONObject map = new JSONObject(config);
            Jedis jedis = new Jedis(map.getString("jedisip"));
            jedis.auth(map.getString("password"));
            // code to make a kafka consumer subscribe to a topic given in config input
            while(true) {
                //forever running code which polls using a kafka consumer
            }
        }
        catch(JedisException j) {
            throw new JedisException("Some msg");
        }
    }
}

endpoint。Java语言

@Controller
public class Endpoint {
    @Autowired
    private createBucket service;

    private Future<String> out;
    private HashMap<String, Future<String>> maps = new HashMap<>();

    @PostMapping(value = "/start", consumes = "application/json", produces = "application/json")
    public ResponseEntity<String> starttask(@RequestBody String conf) {
        try {
        out = service.start(conf);
        maps.put(conf, out);
    }
    catch (Exception e) {
        return new ResponseEntity<>("exception", HttpStatus.BAD_REQUEST);
    }
        return new ResponseEntity<>("{\"started\":\"true\"}", HttpStatus.CREATED);
    }
}

共有1个答案

林鹭洋
2023-03-14

正如官方文档中所述,AsyncUncaughtExceptionHandler用于void返回值。https://docs.spring.io/spring/docs/5.1.10.RELEASE/spring-framework-reference/integration.html#spring-集成

在您的场景中,我建议使用CompletableFuture和DeferredResult:

    @Async
    public CompletableFuture<String> start(String config) {
        CompletableFuture completableFuture = new CompletableFuture();
        try {
            JSONObject map = new JSONObject(config);
            Jedis jedis = new Jedis(map.getString("jedisip"));
            jedis.auth(map.getString("password"));
            completableFuture.complete("started!");
        }
        catch(JedisException j) {
            completableFuture.completeExceptionally(j);
        }

        return completableFuture;
    }
    @PostMapping(value = "/start", consumes = "application/json", produces = "application/json")
    public DeferredResult<ResponseEntity> starttask(@RequestBody String conf) {

        CompletableFuture<String> start = service.start(conf);

        DeferredResult<ResponseEntity> deferredResult = new DeferredResult<>();

        start.whenComplete((res, ex) -> {
            if (ex == null) {
                ResponseEntity<String> successEntity = new ResponseEntity<>("{\"started\":\"true\"}", HttpStatus.CREATED);\
                deferredResult.setResult(successEntity);
            } else {
                // handle ex here!
                ResponseEntity<String> exEntity = new ResponseEntity<>("exception", HttpStatus.BAD_REQUEST);
                deferredResult.setResult(exEntity);
            }
        });

        return deferredResult;

    }

还有一个严重的问题。下面的代码不是线程安全的。

private Future<String> out;
private HashMap<String, Future<String>> maps = new HashMap<>();
 类似资料:
  • TestController使用一个TestService,它有一个Spring@async asyncComp.getGood(s)方法。当输入字符串不是“good”时,会引发异常。TestController将获得异常,在其余响应中,状态500内部服务器错误。我找不到我项目的确切代码,但找到了一些关于使用CompletableFuture的想法。在答案区域,我发布了我写的作为测试应用程序的内容

  • 我已经使用C#(库项目)和Aspect(AOP)编写了Azure函数v1用于日志记录。我在catch块中没有得到异常。 捕获异步方法引发的异常 我有上面讨论的相同问题,但Azure函数运行方法是异步任务,其异常处理和异步void相同。不确定哪里有问题?假设这是函数SDK问题。 Azure函数 记录器方面 解决方法:当我从Azure函数中删除异步等待并通过“getWaiter().GetResult

  • 我通过激发Baeldung在Spring Security页面上的防止暴力身份验证尝试,为我的登录服务实现了暴力阻止机制,如下所示: 当用户未经验证时,LoginService抛出InvalidCredentialException(),然后我试图在AuthenticationFailureListener类中捕获此异常: 当出现错误时,则登录测试服务。将调用loginFailed()方法。然而,

  • 在包含JavaFX警报的类上运行一些单元测试,我实现了以下try-的块: 在对也没有修复它的调用代码进行顶级尝试捕获之后。 叠: 有什么方法可以解决这个问题? 我从错误中得到的是,没有JavaFX场景/舞台可以与警报关联,但我不确定如何处理这一点。

  • 所以 我有一个函数,有一个回调,所以我把它包装在一个挂起函数使用,但当它错误了,它是崩溃整个应用程序。 这里有一个概念是正在发生的事情。 2022-03-04 16:09:45.410 19289-19438/in.app.androidE/AndreidRuntime: FATAL EXCEPTION: DefaultDispatcher-Worers-3进程:in.app.android,PI

  • 我对异步方法有一个奇怪的问题。如果我以异步方式运行它并且它的作业抛出一些特定的异常,它不会显示它并简单地停止执行(没有捕获,没有日志)。 我发现它可以使用jasperreport。这是故障块代码: 如果此代码位于异步注释方法内,则不会引发异常,也不会记录(只是停止执行)。如果删除异步注释,它会抛出以下内容: 我的问题不是异常本身,而是为什么异步方法抓不到它?