Java Spring - 异步回调函数如何返回?

4

我正在使用Spring(Java)和Firebase开发后端。我们使用Firebase令牌(作为身份验证标头附加)来识别用户,使用内置UID (链接1)

不幸的是,从令牌中提取此UID必须异步完成,因此我只能从onSuccess回调中获取令牌。 为了提供响应,我必须从下面的deleteUser方法返回对象,但是在获得成功/失败回调之前,我无法知道响应将是什么!

我可以想象一种通过等待由回调设置的标志或使用一些混乱的时间来完成此操作的方法,但我想知道是否有一种处理此问题的简洁方式,而不会引入竞争条件或大量额外的代码。有人能帮忙吗?

请求映射(处理请求、提供响应)

    @RequestMapping(value = "/users", method = RequestMethod.DELETE)
    public @ResponseBody String deleteUser(@RequestHeader("Authentication") String token) {
        FirebaseUtil.getUid(token, new OnSuccessListener<FirebaseToken>() {
            @Override
            public void onSuccess(FirebaseToken decodedToken) {
                String uid = decodedToken.getUid();
                //RETURN SUCCESSFUL HERE
            }
        }, new OnFailureListener() {
            @Override
            public void onFailure(@NonNull Exception e) {
                //RETURN FAILURE HERE
            }
        });

        //MUST RETURN SOMETHING HERE?
        User userToDelete = userDao.get(uid); //DONT HAVE THE uid HERE
        userDao.delete(uid);
        clearUserAccounts(userToDelete);
        return uid + " was deleted";
    }

FirebaseUtil.getUid()

public static void getUid(String token, OnSuccessListener<FirebaseToken> successListener, OnFailureListener failureListener) {
        FirebaseAuth.getInstance()
                .verifyIdToken(token)
                .addOnSuccessListener(successListener)
                .addOnFailureListener(failureListener);
    }
1个回答

7

虽然有一些方法可以阻塞线程直到异步请求完成,但自Spring 3.2以来,有一种简单且更具资源效率的解决方案。

你可以使用DeferredResult<T>作为返回类型来启用异步处理。这使得Servlet容器可以立即重用HTTP工作线程,同时避免了强制序列化一系列异步请求所带来的麻烦。

通过填写注释,你的代码将如下所示:

@RequestMapping(value = "/users", method = RequestMethod.DELETE)
public DeferredResult<String> deleteUser(@RequestHeader("Authentication") String token) {
    final DeferredResult<String> result = new DeferredResult<>();

    FirebaseUtil.getUid(token, new OnSuccessListener<FirebaseToken>() {
        @Override
        public void onSuccess(FirebaseToken decodedToken) {
            String uid = decodedToken.getUid();
            User userToDelete = userDao.get(uid);
            userDao.delete(uid);
            clearUserAccounts(userToDelete);
            result.setResult(uid + " was deleted");
        }
    }, new OnFailureListener() {
        @Override
        public void onFailure(@NonNull Exception e) {
            result.setErrorResult(e);
        }
    });

    return result;
}

谢谢 - 我最近也发现了Callables,它们似乎以类似的方式工作,但需要覆盖call()?它们会起作用吗?如果不行,为什么?http://xpadro.blogspot.ca/2015/07/understanding-callable-and-spring.html - David Ferris
1
不错的发现。正如博客文章所指出的那样,可调用对象是相似的,但它们并不适用于您的问题。可调用对象必须包装一个(可能长时间运行的)_同步_请求,而 Firebase 方法则是纯异步的。 - vzsg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接