2011-10-31 17 views
11

サーブレット3.0とその非同期サポートに基づくCometパターンを使用して簡単なチャットを実装しようとしています。サーブレット3 Tomcat 7での非同期タスク

私はこの記事に触発されています: http://www.javaworld.com/javaworld/jw-02-2009/jw-02-servlet3.html?page=3

私のサーブレットは、このようになります。私は、コンテナの開始時に私のそれの凍結を始めているとき

@WebListener 
public class ChatPushService implements ServletContextListener { 

     @Override 
     public void contextInitialized(ServletContextEvent sce) { 
       final List<AsyncContext> watchers = new ArrayList<AsyncContext>(); 
      sce.getServletContext().setAttribute("watchers", watchers); 
       // store new messages not published yet 
      Queue<String> messages = new ConcurrentLinkedQueue<String>(); 
      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(); 
             } 
            } 
           }); 
          } 
         } 
       }); 
       } 
     } 

    } 
    } 

@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<AsyncContext> watchers = (List<AsyncContext>) 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<String> messages = (Queue<String>)appScope.getAttribute("messages"); 
      messages.add(someMessage); 
    } 
} 

今私のリスナーは、次のようになります。

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機能はバックグラウンドで非同期に実行されていないと、さらにコンテナの初期化をブロックしているように見えます。

なぜですか?

誰でもこの問題について私を助けることができますか?

答えて

8

whileループ実行中ですcontextInitialized()メソッドが間違っています。 contextInitialized()は、アプリケーションの起動の一部としてServlet Containerによって呼び出されますが、whileループを使用するとアプリの起動がブロックされます。コードなどContextListenerがいるので...私はラメシュのコードにコメントすることはできませんので、私はここでそれを配置する必要がありウォッチャー

@WebListener 
public class ChatPushService implements ServletContextListener { 

    @Override 
    public void contextInitialized(ServletContextEvent sce) { 
      final List<AsyncContext> watchers = new ArrayList<AsyncContext>(); 
     sce.getServletContext().setAttribute("watchers", watchers); 
      // store new messages not published yet 
     Queue<String> messages = new ConcurrentLinkedQueue<String>(); 
     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<AsyncContext> watchers = (List<AsyncContext>) servletCtx.getAttribute("watchers"); 
    Queue<String> messages = (Queue<String>)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(); 
            } 
           } 
          }); 
         } 
        } 
      }); 
      } 
    } 

} 

} 
+0

その部分も私を驚かせましたが、そのコードは、OPがコピーされたJavaworldの記事にそのように表示されました。したがって、OPはここで責任を負うことはありません。 – BalusC

+0

POSTで送信された各メッセージがすべてのクライアントに配信されるチャットを作成しようとしています。このようにキューが作成されています。 –

0

にメッセージを公開する1つのデーモンスレッドを開始 ます修正

ChatManager runnableのスレッドをラップするスレッドはありません。run()をstart()と呼び、start()を呼び出さないといけないと思います。また、かなり明白ですが、新しいChatManager()でなくてはなりません。新しいchatManager()ではなく、Javaの大文字と小文字が区別されています。