【问题标题】:How to get ResourceResolver in a background thread?如何在后台线程中获取 ResourceResolver?
【发布时间】:2018-07-27 18:49:29
【问题描述】:

我正在开发 Adob​​e Experience Manager (AEM) 中的解决方案,该解决方案接收包含文件 URL 的 HTTP 请求,我想下载该文件并将其存储在 JCR 中。

所以,我有一个接收请求的 servlet。它产生一个线程,以便我可以在后台进行下载,然后重定向到确认页面。这使我可以在尝试下载文件时将用户发送到他们的路上,而无需等待。

我可以很好地下载文件,但我无法从我的线程获取可用的 ResourceResolver 将文件存储在 JCR 中。

一开始我只是简单的在后台线程中引用了请求的ResourceResolver:

Servlet:

public void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response)
throws ServletException, IOException {
    ...
    signingProvider.getDocFromService(params, request.getResourceResolver());
    response.sendRedirect(confirmationPage);
}

在提供者类中:

public void getDocFromService(Map<String, String> params, ResourceResolver resolver) {
    new Thread( new Runnable() {
        public void run() {
            Session session = null;
            if (resolver != null) { 
                session = resolver.adaptTo(Session.class); 
                Node root = session.getRootNode();
                ...
            }
        }
    }
}

但这没有用。在阅读了解析器与线程之后,我认为创建一个新的解析器实例会更好,所以我尝试注入一个 ResourceResolverFactory:

Servlet:

signingProvider.getDocFromService(params);

提供者:

public void getDocFromService(Map<String, String> params) {
    new Thread( new Runnable() {
        @Reference
        private ResourceResolverFactory resolverFactory;

        // security hole, fix later
        ResourceResolver resolver = resolverFactory.getAdministrativeResourceResolver(null);
        Session session = null;
        if (resolver != null) {
            session = resolver.adaptTo(Session.class);
            Node root = session.getRootNode();
            ...
        }
    }
}

但是 ResourceResolverFactory 为空,所以当我向它询问解析器时崩溃了。显然,没有工厂被注入@Reference

我真的不想在主线程上做这些工作;下载文件后,我将转身从 JCR 中读取它并将其复制到其他地方。这两个操作都可能很慢或失败。我在原始 URL 处有该文件的副本,因此最终用户不必关心我的下载/上传是否有问题。我只想向他们发送确认信息,以便他们继续开展业务。

关于如何在单独的线程中获取 ResourceResolver 的任何建议?

【问题讨论】:

    标签: java osgi aem sling jcr


    【解决方案1】:

    对于诸如后期\后台处理之类的事情,您可以使用 Sling Jobs。详情请参考documentation

    【讨论】:

    • 这是一个比创建线程更好的主意。但是您应该添加一个代码示例或将此作为注释。这并不是这个问题的真正答案。只是一个评论。 (我没有否决这个答案)
    • 我们这个游戏有这样的规则吗? :) 我认为这家伙能够使用官方文档中的代码示例自己完成。不是火箭科学……
    • @DaniilStelmakh 谢谢,这是一个很好的建议 - 并提醒我,通常最好说明我正在尝试解决的问题,而不是给我带来麻烦的解决方案。由于它已经构建并且正在运行,我现在将使用我的线程解决方案,但很快会考虑将其转换为 Sling Job。你是对的——一个文档链接就足以让我开始。
    【解决方案2】:

    注意:@daniil-stelmakh 在他的回答中提出了一个很好的观点,吊索作业更适合您的目的,添加到他的答案中,这里是一个演示吊索作业的吊索教程:https://sling.apache.org/documentation/tutorials-how-tos/how-to-manage-events-in-sling.html

    直接回答您的问题:

    问题,实际上是@Reference 注释的位置。 该注解由Maven SCR Plugin 处理,它应该放置在“@Component”注解类的私有成员上。

    基本上将您的ResourceResolverFactory 声明移动到您的类的私有成员,而不是线程。

    @Component(
        label = "sample service",
        description = "sample service"
    )
    @Service
    public class ServiceImpl {
        @Reference
        private ResourceResolverFactory resolverFactory;
    
        public void getDocFromService(Map<String, String> params) {
            new Thread( new Runnable() {
    
               // security hole, fix later
               ResourceResolver resolver = resolverFactory.getAdministrativeResourceResolver(null);
               Session session = null;
               if (resolver != null) {
                   session = resolver.adaptTo(Session.class);
                   Node root = session.getRootNode();
                   ...
               }
           }
        }
    }
    

    【讨论】:

    • 我的问题是 ResourceResolverFactory 没有被注入,并且为空,因此在尝试调用 resourceResolverFactory.get 时我得到了 NPE
    • 正在研究这种方法和另一种方法,但快要离开假期周末了,所以可能会在周二开始。我会更新并让你知道什么有效。感谢您的帮助,非常感谢!
    • 不知道为什么,但是@Reference 现在可以工作了——它注入了工厂,现在甚至新线程也获得了 ResourceResolverFactory。
    • getAdministrativeResourceResolver 已弃用。您可能想改用 getServiceResourceResolver。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-04-01
    • 2019-05-20
    • 1970-01-01
    • 2013-01-29
    • 2017-11-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多