2009-10-29 41 views
7

Tôi cần tạo hàng đợi thông báo không đồng bộ trong Java. Trường hợp sử dụng của tôi đang gửi email qua nhiều máy chủ SMTP: Tôi cần phải thực thi các email đó đến cùng một máy chủ SMTP là các quá trình tuần tự, nhưng các email đến các máy chủ SMTP khác nhau có thể được xử lý đồng thời. Tôi đã sử dụng JMS trong quá khứ, nhưng theo như tôi có thể thấy nó chỉ cho phép tạo hàng đợi thời gian biên dịch, trong khi tôi cần tạo hàng đợi khi chạy (một hàng đợi cho mỗi máy chủ SMTP).Tự động tạo hàng đợi thông báo không đồng bộ trong Java

Tôi có thiếu thứ gì đó liên quan đến JMS hoặc có một số công cụ/đề xuất khác mà tôi nên xem không?

+0

Bạn đang sử dụng JMS cụ thể hoặc là cái gì đó mà bạn có thể sử dụng java.util.concurrent và ExecutorServices để làm? –

+0

Tôi không sử dụng JMS cụ thể, vì vậy tôi sẽ xem xét các ExecutorServices, cảm ơn. – Zecrates

Trả lời

6

Tôi đồng ý với Adam, trường hợp sử dụng có vẻ như JMS ở trên cao. Tính năng tích hợp sẵn Java đầy đủ:

package de.mhaller; 

import java.util.ArrayDeque; 
import java.util.ArrayList; 
import java.util.Deque; 
import java.util.HashMap; 
import java.util.Map; 
import java.util.Queue; 
import java.util.concurrent.ExecutorService; 
import java.util.concurrent.Executors; 
import java.util.concurrent.LinkedBlockingDeque; 

import org.junit.Assert; 
import org.junit.Test; 

public class Mailer { 

    @Test 
    public void testMailer() throws Exception { 
     ExecutorService executor = Executors.newCachedThreadPool(); 
     ArrayList<Mail> log = new ArrayList<Mail>(); 
     LinkedBlockingDeque<Mail> incoming = new LinkedBlockingDeque<Mail>(); 

     // TODO: Put mails to be sent into the incoming queue 
     incoming.offer(new Mail("[email protected]", "localhost")); 
     incoming.offer(new Mail("[email protected]", "otherhost")); 
     incoming.offer(new Mail("[email protected]", "otherhost")); 
     incoming.offer(new Mail("[email protected]", "localhost")); 

     Map<Mailserver, Queue<Mail>> queues = new HashMap<Mailserver, Queue<Mail>>(); 
     while (!incoming.isEmpty()) { 
      Mail mail = incoming.pollFirst(); 
      Mailserver mailserver = findMailserver(mail); 
      if (!queues.containsKey(mailserver)) { 
       ArrayDeque<Mail> serverQueue = new ArrayDeque<Mail>(); 
       queues.put(mailserver, serverQueue); 
       executor.execute(new SendMail(mailserver, serverQueue)); 
      } 
      Queue<Mail> slot = queues.get(mailserver); 
      slot.offer(mail); 
     } 

     assertMailSentWithCorrectServer(log); 
    } 

    private void assertMailSentWithCorrectServer(ArrayList<Mail> log) { 
     for (Mail mail : log) { 
      if (!mail.server.equals(mail.sentBy.mailserver)) { 
       Assert.fail("Mail sent by wrong server: " + mail); 
      } 
     } 
    } 

    private Mailserver findMailserver(Mail mail) { 
     // TODO: Your lookup logic which server to use 
     return new Mailserver(mail.server); 
    } 

    private static class Mail { 
     String recipient; 
     String server; 
     SendMail sentBy; 

     public Mail(String recipient, String server) { 
      this.recipient = recipient; 
      this.server = server; 
     } 

     @Override 
     public String toString() { 
      return "mail for " + recipient; 
     } 
    } 

    public static class SendMail implements Runnable { 

     private final Deque<Mail> queue; 
     private final Mailserver mailserver; 

     public SendMail(Mailserver mailserver, Deque<Mail> queue) { 
      this.mailserver = mailserver; 
      this.queue = queue; 
     } 

     @Override 
     public void run() { 
      while (!queue.isEmpty()) { 
       Mail mail = queue.pollFirst(); 
       // TODO: Use SMTP to send the mail via mailserver 
       System.out.println(this + " sent " + mail + " via " + mailserver); 
       mail.sentBy = this; 
      } 
     } 

    } 

    public static class Mailserver { 
     String hostname; 

     public Mailserver(String hostname) { 
      this.hostname = hostname; 
     } 

     @Override 
     public String toString() { 
      return hostname; 
     } 

     @Override 
     public int hashCode() { 
      return hostname.hashCode(); 
     } 

     @Override 
     public boolean equals(Object obj) { 
      return hostname.equals(((Mailserver) obj).hostname); 
     } 

    } 

} 
1

Bản thân JMS là thông số kỹ thuật khá im lặng về vấn đề này. Hầu hết các triển khai cho phép bạn thực hiện điều này, không chỉ thông qua JMS mà còn sử dụng API của riêng họ. Nhưng bạn sẽ không thể kết nối một thứ gì đó chính thức như MDB với hàng đợi động. Thay vào đó, bạn sẽ cần phải quản lý các kết nối và người nghe của riêng bạn.

1

Lần cuối cùng chúng tôi xem xét điều này trong môi trường WebSphere, thật khó khăn/không thể tạo hàng đợi động (hàng đợi tạm thời quá thoáng qua cho bạn). Mặc dù các API tạo hàng đợi tồn tại nhưng chúng yêu cầu máy chủ khởi động lại sau đó để hoạt động. Sau đó, vấn đề MDB được sử dụng.

Làm thế nào về một công việc bẩn xung quanh dựa trên câu ngạn ngữ rằng tất cả các vấn đề có thể được giải quyết bằng một mức độ thêm của indirection, trong đó giả định rằng bộ máy in có sẵn là tương đối nhỏ.

Tạo hàng đợi Printer01 đến Printer99 (hoặc một số nhỏ hơn). Có một "cơ sở dữ liệu" ánh xạ hàng đợi tới các máy in thực. Theo yêu cầu cho máy in đi cùng bạn có thể thêm vào bảng ánh xạ. Bạn có thể có một số chi phí của MDBs nhìn vào hàng đợi mà sẽ không bao giờ được sử dụng, nhưng trừ khi số lượng máy in pootential của bạn là rộng lớn có lẽ bạn có thể đủ khả năng đó?

0

Tạo một danh sách cho mỗi sever SMTP và giới hạn của bạn hàng đợi của người tiêu dùng (MDB hoặc một người biết lắng nghe thông điệp) tới 1

0

Tôi đã làm điều này với ActiveMQ - Tôi thực sự đăng một câu hỏi về vấn đề này vào thời điểm đó, như Tôi đã có mối quan tâm tương tự (tài liệu JMS tại thời điểm nói rằng điều này không được hỗ trợ) và được đảm bảo rằng nó đã được hỗ trợ.

+0

Bạn có liên kết đến câu hỏi của mình hoặc tài liệu mô tả cách đạt được điều này không? – Zecrates

Các vấn đề liên quan