Tomcat 7上的Servlet 3异步任务

我正在尝试使用基于其异步支持的Servlet 3.0和Comet模式实现简单聊天。

我受到这篇文章的启发: http : //www.javaworld.com/javaworld/jw-02-2009/jw-02-servlet3.html?page = 3

我的servlet看起来像这样。

@WebServlet(name="chatServlet", urlPatterns={"/ChatServlet"}, asyncSupported=true) public class ChatServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { AsyncContext aCtx = request.startAsync(request, response); ServletContext appScope = request.getServletContext(); List watchers = (List) appScope.getAttribute("watchers"); watchers.add(aCtx); //register the watcher } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { AsyncContext aCtx = request.startAsync(request, response); ServletContext appScope = request.getServletContext(); Queue messages = (Queue)appScope.getAttribute("messages"); messages.add(someMessage); } } 

现在我的听众看起来像这样:

 @WebListener public class ChatPushService implements ServletContextListener { @Override public void contextInitialized(ServletContextEvent sce) { final List watchers = new ArrayList(); sce.getServletContext().setAttribute("watchers", watchers); // store new messages not published yet Queue messages = new ConcurrentLinkedQueue(); sce.getServletContext().setAttribute("messages", messages); Executor messageExecutor = Executors.newCachedThreadPool(); final Executor watcherExecutor = Executors.newCachedThreadPool(); while(true) { if(!messages.isEmpty()) { System.out.println("notEmpty"); String message = messages.poll(); messageExecutor.execute(new Runnable(){ @Override public void run() { for(final AsyncContext aCtx : watchers){ watcherExecutor.execute(new Runnable(){ @Override public void run() { try { aCtx.getResponse().getWriter().print("brrrrr"); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }); } } }); } } } } 

当我开始时,它在容器启动期间冻结。

 Nov 1, 2011 1:12:09 AM org.apache.catalina.core.AprLifecycleListener init INFO: The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: /usr/lib/jvm/java-6-openjdk/jre/lib/amd64/server:/usr/lib/jvm/java-6-openjdk/jre/lib/amd64:/usr/lib/jvm/java-6-openjdk/jre/../lib/amd64:/usr/java/packages/lib/amd64:/usr/lib/jni:/lib:/usr/lib Nov 1, 2011 1:12:09 AM org.apache.tomcat.util.digester.SetPropertiesRule begin WARNING: [SetPropertiesRule]{Server/Service/Engine/Host/Context} Setting property 'source' to 'org.eclipse.jst.jee.server:Servlet3Comet' did not find a matching property. Nov 1, 2011 1:12:09 AM org.apache.coyote.AbstractProtocol init INFO: Initializing ProtocolHandler ["http-bio-8080"] Nov 1, 2011 1:12:09 AM org.apache.coyote.AbstractProtocol init INFO: Initializing ProtocolHandler ["ajp-bio-8009"] Nov 1, 2011 1:12:09 AM org.apache.catalina.startup.Catalina load INFO: Initialization processed in 624 ms Nov 1, 2011 1:12:09 AM org.apache.catalina.core.StandardService startInternal INFO: Starting service Catalina Nov 1, 2011 1:12:09 AM org.apache.catalina.core.StandardEngine startInternal INFO: Starting Servlet Engine: Apache Tomcat/7.0.22 

看起来像public void contextInitialized函数没有在后台异步运行,并且阻止了进一步的容器初始化。

为什么?

谁可以帮我解决这个问题?

你在contextInitialized()方法中运行while循环是错误的。 contextInitialized()作为应用程序启动的一部分由Servlet Container调用,while循环将阻止您的应用程序启动。

修改了代码,使得ContextListener将启动一个守护程序线程,该守护程序线程将消息发布给观察者

 @WebListener public class ChatPushService implements ServletContextListener { @Override public void contextInitialized(ServletContextEvent sce) { final List watchers = new ArrayList(); sce.getServletContext().setAttribute("watchers", watchers); // store new messages not published yet Queue messages = new ConcurrentLinkedQueue(); sce.getServletContext().setAttribute("messages", messages); new chatManager(sce.getServletContext()).start(); //START DAEMON } } public class ChatManager implements Runnable { ServletContext servletCtx; public ChatManager(ServletContext ctx) { this.servletCtx = ctx; } public void run() { List watchers = (List) servletCtx.getAttribute("watchers"); Queue messages = (Queue)appScope.getAttribute("messages"); Executor messageExecutor = Executors.newCachedThreadPool(); final Executor watcherExecutor = Executors.newCachedThreadPool(); while(true) { if(!messages.isEmpty()) { System.out.println("notEmpty"); String message = messages.poll(); messageExecutor.execute(new Runnable(){ @Override public void run() { for(final AsyncContext aCtx : watchers){ watcherExecutor.execute(new Runnable(){ @Override public void run() { try { aCtx.getResponse().getWriter().print("brrrrr"); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }); } } }); } } } } 

我不能评论Ramesh的代码,所以我必须把它放在这里…因为没有线程包围ChatManager runnable,我相信你应该调用run()而不是start()。 另外,很明显,它应该是新的ChatManager()..而不是新的chatManager()… Java帐户区分大小写。