簡體   English   中英

在Java中動態創建異步消息隊列

[英]Dynamically creating asynchronous message queues in Java

我需要在Java中動態創建異步消息隊列。 我的用例是通過多個SMTP服務器發送電子郵件:我需要按順序強制執行相同SMTP服務器的電子郵件,但可以同時處理發送到不同SMTP服務器的電子郵件。 我以前使用過JMS,但據我所知它只允許編譯時隊列創建,而我需要在運行時創建隊列(每個SMTP服務器一個隊列)。

我是否遺漏了有關JMS的內容,或者是否有其他工具/建議我應該查看一下?

我同意Adam,用例聽起來像JMS是開銷。 Java內置功能足夠:

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("foo1@localhost", "localhost"));
        incoming.offer(new Mail("foo2@otherhost", "otherhost"));
        incoming.offer(new Mail("foo3@otherhost", "otherhost"));
        incoming.offer(new Mail("foo4@localhost", "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);
        }

    }

}

作為規范的JMS本身在這個問題上相當沉默。 大多數實現允許您執行此操作,而不是通過JMS本身,而是使用自己的API。 但是,您無法將像MDB這樣的正式內容連接到動態隊列。 相反,您需要管理自己的連接和監聽器。

我們最后一次在WebSphere環境中查看它時,動態創建隊列是非常困難/不可能的(我認為臨時隊列對你來說太短暫了)。 雖然存在用於創建隊列的API,但是之后需要重新啟動服務器才能變為活動狀態。 然后就是MDB問題。

如何通過額外的間接級別解決所有問題來解決所有問題的骯臟變通方法,這假設可用打印機的集合相對較小。

創建隊列Printer01到Printer99(或一些較小的數字)。 有一個“隊列”,將隊列映射到真正的打印機。 隨着打印機的請求出現,您可以添加到映射表。 您可能會有一些MDB查看永遠不會使用的隊列的開銷,但除非你的潛在數量很大的打印機,否則你可以負擔得起嗎?

為每個SMTP服務器和限制隊列使用者(MDB或消息偵聽器)創建一個隊列為1

我用activemq完成了這個 - 我當時實際上已經發布了一個問題,因為我有類似的問題(當時的JMS文檔聲明這不受支持)並且確信它得到了支持。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM