带有异步 Servlets 的嵌入式 Jetty 9 在 org.eclipse.jetty.server.Reques



我有一个使用嵌入式 Jetty 9.2.6 和带注释的异步 Servlet 的应用程序(我使用 Facelet 来创建界面模板(。当我使用 asyncSupported = true 访问任何 Servlet 时,会发生随机异常。

下面是随机异常的一个堆栈跟踪:

09:31:42.801 [qtp1262773598-20] DEBUG c.d.a.v.c.CitiesPerStateServlet - APPTEST-BUG
java.lang.NullPointerException: null
    at org.eclipse.jetty.server.Request.extractFormParameters(Request.java:326) ~[jetty-server-9.2.6.v20141205.jar:9.2.6.v20141205]
    at org.eclipse.jetty.server.Request.extractContentParameters(Request.java:302) ~[jetty-server-9.2.6.v20141205.jar:9.2.6.v20141205]
    at org.eclipse.jetty.server.Request.extractParameters(Request.java:256) ~[jetty-server-9.2.6.v20141205.jar:9.2.6.v20141205]
    at org.eclipse.jetty.server.Request.getParameter(Request.java:827) ~[jetty-server-9.2.6.v20141205.jar:9.2.6.v20141205]
    at com.doitlabs.app99vendas.view.controller.CitiesPerStateServlet$1.run(CitiesPerStateServlet.java:55) ~[classes/:na]
    at org.eclipse.jetty.server.handler.ContextHandler.handle(ContextHandler.java:1173) [jetty-server-9.2.6.v20141205.jar:9.2.6.v20141205]
    at org.eclipse.jetty.server.AsyncContextState$2.run(AsyncContextState.java:168) [jetty-server-9.2.6.v20141205.jar:9.2.6.v20141205]
    at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:626) [jetty-util-9.2.6.v20141205.jar:9.2.6.v20141205]
    at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:546) [jetty-util-9.2.6.v20141205.jar:9.2.6.v20141205]
    at java.lang.Thread.run(Thread.java:745) [na:1.8.0_20]

这是我在堆栈跟踪中引用的 Servlet:

@WebServlet(urlPatterns = { "/controllers/cities-per-state" }, asyncSupported = true)
public class CitiesPerStateServlet extends HttpServlet {
    final Logger LOGGER = LoggerFactory.getLogger(CitiesPerStateServlet.class);
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.processRequest(req, resp);
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.processRequest(req, resp);
    }   
    private void processRequest(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        AsyncContext ac = req.startAsync(req, resp);
        ac.start(new Runnable() {
            @Override
            public void run() {
                HttpServletRequest req_ = (HttpServletRequest)ac.getRequest();
                try {
                    String           stateId = req_.getParameter("state_id");
                    Collection<City> cities   = null;
                    if (stateId != null) {
                       cities = CityDAO.retrieveByState(new Long(stateId));
                    }
                    req_.setAttribute("cities", cities);
                    ac.dispatch("/pages/system-ops/campaign/cities-per-state.xhtml");
                } catch (Exception e) {
                    if (LogUtil.shouldLog(e)) {
                        LOGGER.debug(BUG, e);
                    }                    
                }                    
            }
        });    
    }
}

以下是我如何启动嵌入式码头:

public class Main {
    public static void main(String[] args) throws Exception {
        String webappDirLocation = "./src/main/webapp/";
        String webPort = System.getenv("PORT");
        if (webPort == null || webPort.isEmpty()) {
            webPort = "8080";
        }
        Server server = new Server(Integer.valueOf(webPort));
        ClassList classlist = org.eclipse.jetty.webapp.Configuration.ClassList.setServerDefault(server);
        classlist.addBefore("org.eclipse.jetty.webapp.JettyWebXmlConfiguration", "org.eclipse.jetty.annotations.AnnotationConfiguration");
        WebAppContext context = new WebAppContext();
        context.setAttribute("org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern", ".*/classes/.*");
        context.setDescriptor(webappDirLocation + "/WEB-INF/web.xml");
        context.setBaseResource(new ResourceCollection(new String[] { webappDirLocation, "./target" }));
        context.setResourceAlias("/WEB-INF/classes/", "/classes/");
        context.setContextPath("/");
        context.setParentLoaderPriority(true);
        server.setHandler(context);
        server.start();
        server.join();
    }
}

网络.xml文件:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
             version="3.1">   
    <!-- Parameters ######################################################## --> 
    <context-param>
        <param-name>javax.faces.DEFAULT_SUFFIX</param-name>
        <param-value>.xhtml</param-value>
    </context-param>
    <context-param>
        <param-name>javax.faces.FACELETS_SKIP_COMMENTS</param-name>
        <param-value>true</param-value>
    </context-param>
    <!-- Servlet mappings ################################################## --> 
    <servlet-mapping>
        <servlet-name>Faces Servlet</servlet-name>
        <url-pattern>*.xhtml</url-pattern>
    </servlet-mapping>
    <servlet>
        <servlet-name>Faces Servlet</servlet-name>
        <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <!-- Listerners ######################################################## -->
    <listener>
        <listener-class>
            com.sun.faces.config.ConfigureListener
        </listener-class>
    </listener>
    <!-- Session config #################################################### -->
    <session-config>
        <session-timeout>15</session-timeout>
    </session-config>

    <!-- Welcome ########################################################### -->
    <welcome-file-list>
        <welcome-file>index.xhtml</welcome-file>
    </welcome-file-list>
</web-app>

这是一个Maven项目,所以这是我的POM.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.doitlabs.app99vendas</groupId>
    <version>1.0-SNAPSHOT</version>
    <name>app99vendas.net</name>
    <artifactId>99vendas.net</artifactId>
    <packaging>jar</packaging>
    <properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-server</artifactId>
            <version>9.2.6.v20141205</version>
        </dependency>        
        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-jsp</artifactId>
            <version>9.2.6.v20141205</version>
        </dependency>
        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-maven-plugin</artifactId>
            <version>9.2.6.v20141205</version>
        </dependency>
        <dependency>
            <groupId>com.sun.faces</groupId>
            <artifactId>jsf-api</artifactId>
            <version>2.2.8</version>
        </dependency>
        <dependency>
            <groupId>com.sun.faces</groupId>
            <artifactId>jsf-impl</artifactId>
            <version>2.2.8</version>
        </dependency>
        <dependency>
            <groupId>org.eclipse.persistence</groupId>
            <artifactId>org.eclipse.persistence.jpa</artifactId>
            <version>2.5.2</version>
        </dependency>          
        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <version>9.3-1102-jdbc41</version>
        </dependency>
        <dependency>
            <groupId>com.mandrillapp.wrapper.lutung</groupId>
            <artifactId>lutung</artifactId>
            <version>0.0.5</version>
        </dependency> 
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.3</version>
        </dependency>                     
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.3.5</version>
        </dependency>                  
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.4</version>
        </dependency>   
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.2</version>
        </dependency>
        <dependency>
            <groupId>com.thoughtworks.xstream</groupId>
            <artifactId>xstream</artifactId>
            <version>1.4.7</version>
        </dependency>
        <dependency> 
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.0.13</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <version>2.8</version>
                <executions>
                    <execution>
                        <id>copy-dependencies</id>
                        <phase>package</phase>
                        <goals>
                            <goal>copy-dependencies</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

有谁知道为什么会这样?

如果您需要更多信息,请告诉我。

提前感谢!

AsyncContext中的HttpServletRequestHttpServletResponse对象的访问与AsyncContext外部的访问不同(它们不是线程安全的,甚至可以在AsyncContext生命周期完成之前回收(。 事实上,大多数容器在AsyncContext启动后立即出于垃圾回收的原因回收它们所能回收的东西。

将此与HttpServletRequest.getParameter(String name)行为相结合(这还需要读取请求正文内容以获取任何可能的参数(,并且您需要更改代码。

建议您在调用startAsync()之前从HttpServletRequest中读取该信息,并将该信息传递到您的AsyncListener.onStartAsync()Runnable实现中。

相关内容

  • 没有找到相关文章

最新更新