2011-10-31 15 views
11

Tôi đang cố gắng triển khai Trò chuyện đơn giản bằng Servlet 3.0 và mẫu Comet dựa trên hỗ trợ không đồng bộ của nó.Servlet 3 Nhiệm vụ không đồng bộ trên Tomcat 7

Tôi lấy cảm hứng từ bài viết này: http://www.javaworld.com/javaworld/jw-02-2009/jw-02-servlet3.html?page=3

servlet của tôi trông như thế này.

@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); 
    } 
} 

tại Listener của tôi trông như thế này:

@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(); 
             } 
            } 
           }); 
          } 
         } 
       }); 
       } 
     } 

    } 
    } 

Khi tôi bắt đầu đóng băng của tôi nó trong thời gian khởi container.

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 

Có vẻ như chức năng public void contextInitialized không chạy không đồng bộ trên nền và đang chặn việc khởi tạo vùng chứa tiếp theo.

Tại sao?

ai cũng có thể giúp tôi về vấn đề này?

Trả lời

8

Bạn đang chạy trong khi vòng lặp bên trong contextInitialized() phương pháp sai. contextInitialized() được gọi bởi Servlet Container như là một phần của quá trình khởi động ứng dụng, trong khi vòng lặp while sẽ chặn ứng dụng của bạn bắt đầu.

Modified mã như vậy ContextListener sẽ bắt đầu một daemon thread mà công bố những thông điệp đến người xem

@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

Phần đó cũng làm tôi ngạc nhiên, nhưng mã đó được trình bày như vậy trong bài viết của Javaworld mà OP đã sao chép, vì vậy OP không phải là nguyên nhân gây ra ở đây. – BalusC

+0

Tôi đang cố gắng tạo trò chuyện trong đó mỗi tin nhắn được gửi bởi POST sẽ được gửi đến tất cả khách hàng Đã đăng ký ở đó, Vì vậy, loại hàng đợi được tạo và trong khi (true) chặn màn hình nếu thông báo mới này đã có trong hàng đợi. –

0

Tôi không thể bình luận về mã Ramesh, vì vậy tôi phải đặt nó ở đây ... Kể từ không có thread kết thúc tốt đẹp vòng chạy ChatManager, tôi tin rằng bạn nên gọi run() trên nó và không bắt đầu(). Ngoài ra, khá rõ ràng mặc dù, nó phải là mới ChatManager() .. không mới chatManager() ... tài khoản của Java được phân biệt chữ hoa chữ thường.