我有一个使用嵌入式Jetty 9.2.6的应用程序,带有带注释的异步Servlet(我使用Facelets创建接口模板)。当我使用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);
}
}
}
});
}
}
以下是我启动嵌入式Jetty的方法:
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();
}
}
web.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>
有没有人知道为什么会这样?
如果您需要更多信息,请与我们联系。
提前致谢!
答案 0 :(得分:3)
对HttpServletRequest
中HttpServletResponse
和AsyncContext
个对象的访问 与AsyncContext
之外的访问权限相同(他们不是线程安全,甚至可以在AsyncContext
生命周期完成之前回收。事实上,一旦AsyncContext
启动,大多数容器都会回收垃圾收集的原因。
将此与HttpServletRequest.getParameter(String name)
行为结合在一起(此需要以读取请求正文内容以获取任何可能的参数),并且您需要更改代码。
建议您在致电HttpServletRequest
之前阅读startAsync()
中的内容,并将该信息传递到AsyncListener.onStartAsync()
或{{1}实施。