【问题标题】:How to enable Async support for Sling Servlet - Felix如何启用对 Sling Servlet 的异步支持 - Felix
【发布时间】:2022-01-19 01:52:15
【问题描述】:

我有这个代码

  @Component(service = Servlet.class, scope = ServiceScope.PROTOTYPE, property={
    HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_PATTERN+"=/content/*",
    HttpWhiteboardConstants.HTTP_WHITEBOARD_FILTER_ASYNC_SUPPORTED+"=true",
    HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_ASYNC_SUPPORTED+"=true"}
    )
  @SlingServletResourceTypes(
    resourceTypes="cq/Page",
    methods=HttpConstants.METHOD_GET,
    selectors = "asynctest",
    extensions="json")
   public class ReactiveServlet extends HttpServlet {

@Override
protected void doGet(
        HttpServletRequest  request, HttpServletResponse response)
        throws ServletException, IOException {
         AsyncContext async = request.startAsync();
        // Some logic
        }
 }          

当调用这个 servlet /content/mypage.asynctest.json 然后得到这个错误

 java.lang.IllegalStateException: null
at org.apache.felix.http.base.internal.dispatch.ServletRequestWrapper.startAsync(ServletRequestWrapper.java:338) [org.apache.felix.http.jetty:4.1.10]
at javax.servlet.ServletRequestWrapper.startAsync(ServletRequestWrapper.java:369) [org.apache.felix.http.servlet-api:1.1.2]
at javax.servlet.ServletRequestWrapper.startAsync(ServletRequestWrapper.java:369) [org.apache.felix.http.servlet-api:1.1.2]

【问题讨论】:

    标签: osgi aem apache-felix sling


    【解决方案1】:

    简短的回答是 Sling-Servlets 不支持 异步。你的异常在这个类中被抛出:

    https://github.com/apache/felix-dev/blob/master/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/ServletRequestWrapper.java

    @Override
    public AsyncContext startAsync() throws IllegalStateException
    {
        if ( !this.asyncSupported )
        {
            throw new IllegalStateException();
        }
        return super.startAsync();
    }
    

    但是您正在将 OSGi Http-Whiteboard 模式与 Sling-Servlet 混合使用。我不确定,你想做什么。

    Sling/AEM 是一个技术堆栈,其中层建立在层之上。不幸的是,这些层中有多个允许注册 servlet。

    • Sling Servlets = Apache Sling(推荐,默认)
    • OSGi HTTP 白板模式 = Apache Felix(仅适用于特殊情况)
    • JEE Servlet = Jetty Servlet 容器(不推荐)

    Sling-Servlet

    您使用@SlingServletResourceTypes 注册的 Sling-Servlet 不支持异步。以下 servlet 的输出为:Async is not supported by an Sling-Servlet! (http://localhost:4502/content/we-retail.asynctest.json)

    import static org.apache.sling.api.servlets.ServletResolverConstants.*;
    
    import javax.servlet.AsyncContext;
    import javax.servlet.Servlet;
    import javax.servlet.ServletException;
    import java.io.IOException;
    
    import org.apache.sling.api.SlingHttpServletRequest;
    import org.apache.sling.api.SlingHttpServletResponse;
    import org.apache.sling.api.servlets.SlingSafeMethodsServlet;
    import org.osgi.service.component.annotations.Component;
    
    @Component(service = Servlet.class, property = {
            SLING_SERVLET_RESOURCE_TYPES + "=cq:Page",
            SLING_SERVLET_SELECTORS + "=asynctest",
            SLING_SERVLET_EXTENSIONS + "=json",
            SLING_SERVLET_METHODS + "=GET"
    })
    public class AsyncSlingServlet extends SlingSafeMethodsServlet {
    
        @Override
        protected void doGet(
                SlingHttpServletRequest request,
                SlingHttpServletResponse response
        ) throws ServletException, IOException {
    
            if (request.isAsyncSupported() /* false */) {
                final AsyncContext async = request.startAsync();
                async.start(() -> {
                    async.getResponse().setContentType("text/plain");
                    async.getResponse().setCharacterEncoding("utf-8");
                    try {
                        async.getResponse().getWriter().println(
                                "Hello from the Sling-Servlet!");
                    } catch (IOException e) {
                        // ignore
                    }
                    async.complete();
                });
            } else {
                response.setContentType("text/plain");
                response.setCharacterEncoding("utf-8");
                response.getWriter().println(
                        "Async is not supported by an Sling-Servlet!");
            }
        }
    }
    

    OSGi HTTP 白板模式

    通过 OSGi HTTP 白板模式注册的几乎相同的 servlet支持异步。它返回 Hello from the OSGi Http-Whiteboard Servlet! (http://localhost:4502/my-project/hello)。但是这样的 servlet 不属于 Sling,因此它们是“竞争对手”或“竞争对手”。您必须小心,不要对 Sling 产生负面影响。所以应该避免 /content 路径。

    import javax.servlet.AsyncContext;
    import javax.servlet.Servlet;
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    
    import org.osgi.service.component.annotations.Component;
    import org.osgi.service.component.annotations.ServiceScope;
    import org.osgi.service.http.whiteboard.HttpWhiteboardConstants;
    
    @Component(
            service = Servlet.class,
            scope = ServiceScope.PROTOTYPE,
            property = {
                    HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_PATTERN
                            + "=/my-project/*",
                    HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_SELECT
                            + "=("
                            + HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_NAME
                            + "=org.apache.sling)",
                    HttpWhiteboardConstants.HTTP_WHITEBOARD_FILTER_ASYNC_SUPPORTED
                            + "=true",
                    HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_ASYNC_SUPPORTED
                            + "=true" }
    )
    public class AsyncOSGiServlet extends HttpServlet {
    
        @Override
        protected void doGet(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
    
            if (request.isAsyncSupported() /* true */) {
                final AsyncContext async = request.startAsync();
                async.start(() -> {
                    async.getResponse().setContentType("text/plain");
                    async.getResponse().setCharacterEncoding("utf-8");
                    try {
                        async.getResponse().getWriter().println(
                                "Hello from the OSGi Http-Whiteboard Servlet!");
                    } catch (IOException e) {
                        // ignore
                    }
                    async.complete();
                });
            } else {
                response.setContentType("text/plain");
                response.setCharacterEncoding("utf-8");
                response.getWriter().println(
                        "Async is not supported by an OSGi Http-Whiteboard Servlet!");
            }
        }
    }
    

    【讨论】:

    • 太好了,谢谢你的解释,你知道为什么 Sling servlet 不支持这个吗?我猜这可能是因为 JCR Session 不是线程安全的?
    • JCR 会议是一个好点。但可能即使是 Sling 也无法处理它。实际上大多数其他 HTTP 框架也不支持异步。在调用 sling-servlet 之前,Sling-Framework 已经对请求进行了大量处理。它解析资源,应用许多请求过滤器,渲染它,应用许多响应过滤器并对其进行后处理(例如链接重写器)。这一切都不是为异步实现的。只有当上述框架可以释放大部分被阻塞的资源时,异步才有意义。但是 Sling 只是等待渲染 - 整个线程都被阻塞了。
    • 但是:如果需要,您可以增加 Sling 线程的数量。 Java 不是 JavaScript。只有在 JS 中你必须使用异步,因为 JS 是单线程的。
    • 但不是:在 Java 中,长时间运行的线程会产生一些成本。有充分的理由避免它们。但在 JS 中它们是致命的。在 Java 中,它们对性能有轻微影响。
    • 再次感谢,因为 Jetty 容器支持编程的反应性,所以我认为使用 Sling 是可能的。增加 Sling 线程是一种选择,但这种方法与 Ractive 模式不匹配。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-05
    • 2012-06-03
    • 1970-01-01
    • 2018-10-01
    • 2015-12-19
    相关资源
    最近更新 更多