首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Spring 整合 RabbitMQ 實現異步郵件發送完整教學

     編輯:Java 相關知識

為什麼需要訊息佇列?

使用者註冊後發送歡迎信若同步處理,會阻塞回應、降低吞吐量,且若郵件伺服器暫時不可用會導致註冊失敗。引入 RabbitMQ 將「發送郵件」解耦為非同步任務:Producer 將郵件任務投入佇列即刻返回,Consumer 背景消費並重試發送,大幅提升系統韌性與回應速度。

核心概念速覽

  • Producer:發送訊息到 Exchange
  • Exchange:根據 Routing Key 與 Binding 規則路由訊息到 Queue
  • Queue:暫存訊息
  • Consumer:從 Queue 取出訊息處理
  • Binding:Exchange 與 Queue 的對應規則

1. 依賴引入

<dependency>
    <groupId>org.springframework.amqp</groupId>
    <artifactId>spring-amqp</artifactId>
    <version>1.6.0.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework.amqp</groupId>
    <artifactId>spring-rabbit</artifactId>
    <version>1.6.0.RELEASE</version>
</dependency>

2. RabbitMQ 設定檔

<beans:beans xmlns="https://www.springframework.org/schema/rabbit"
    xmlns:beans="https://www.springframework.org/schema/beans"
    xsi:schemaLocation="https://www.springframework.org/schema/rabbit
        https://www.springframework.org/schema/rabbit/spring-rabbit.xsd">

    <!-- 連線工廠,生產環境請改為環境變數 -->
    <connection-factory id="connectionFactory"
        host="localhost" port="5672" username="everSeeker" password="333" />

    <admin connection-factory="connectionFactory" />

    <!-- 宣告 Queue,durable=true 確保重啟不遺失 -->
    <queue id="userAlertEmailQueue" name="user.alerts.email" durable="true" />

    <!-- Direct Exchange:Routing Key 完全匹配 -->
    <direct-exchange name="user.alert.email.exchange" durable="true">
        <bindings>
            <binding queue="user.alerts.email" /> <!-- 預設 routing key = queue name -->
        </bindings>
    </direct-exchange>

    <!-- RabbitTemplate 發送訊息 -->
    <template id="rabbitTemplate" connection-factory="connectionFactory" />

    <!-- Listener Container + Consumer -->
    <beans:bean id="userListener" class="com.example.alerts.UserAlertHandler" />
    <listener-container connection-factory="connectionFactory" acknowledge="auto">
        <listener ref="userListener" method="handleUserAlertToEmail" queues="userAlertEmailQueue" />
    </listener-container>
</beans:beans>

注意:若使用預設 guest/guest 登入會報 ACCESS_REFUSED,請在 RabbitMQ Management UI (https://localhost:15672) 建立具 administrator 權限的用戶並授權虛擬主機。

3. Producer:發送註冊郵件任務

@Service
public class UserAlertServiceImpl implements UserAlertService {
    private final RabbitTemplate rabbitTemplate;

    @Autowired
    public UserAlertServiceImpl(RabbitTemplate rabbitTemplate) {
        this.rabbitTemplate = rabbitTemplate;
    }

    @Override
    public void sendUserAlertToEmail(User user) {
        // 將 User 物件序列化為訊息發送到 Exchange
        rabbitTemplate.convertAndSend("user.alert.email.exchange", "user.alerts.email", user);
    }
}

4. Consumer:消費訊息並發送郵件

@Component
public class UserAlertHandler {
    private final UserMailService mailService;

    @Autowired
    public UserAlertHandler(UserMailService mailService) {
        this.mailService = mailService;
    }

    public void handleUserAlertToEmail(User user) {
        mailService.sendSimpleUserMail(user.getEmail(), user);
    }
}

5. JavaMail 發送郵件設定

依賴

<dependency>
    <groupId>javax.mail</groupId>
    <artifactId>mail</artifactId>
    <version>1.4.7</version>
</dependency>

MailSender Bean 設定(支援 SSL/TLS)

@Bean
public MailSender mailSender(Environment env) {
    JavaMailSenderImpl sender = new JavaMailSenderImpl();
    sender.setHost(env.getProperty("mail.host"));
    sender.setPort(Integer.parseInt(env.getProperty("mail.port")));
    sender.setUsername(env.getProperty("mail.username"));
    sender.setPassword(env.getProperty("mail.password"));
    sender.setDefaultEncoding("UTF-8");

    // SSL 設定(Gmail、QQ 郵箱需啟用)
    Properties props = new Properties();
    props.put("mail.smtp.auth", "true");
    props.put("mail.smtp.starttls.enable", "true");
    props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
    props.put("mail.smtp.socketFactory.port", "465");
    sender.setJavaMailProperties(props);
    return sender;
}

郵件發送服務

@Service
public class UserMailServiceImpl implements UserMailService {
    private final MailSender mailSender;

    @Autowired
    public UserMailServiceImpl(MailSender mailSender) {
        this.mailSender = mailSender;
    }

    @Override
    public void sendSimpleUserMail(String to, User user) {
        SimpleMailMessage msg = new SimpleMailMessage();
        msg.setFrom("noreply@example.com");
        msg.setTo(to);
        msg.setSubject(user.getUsername() + ",歡迎註冊!");
        msg.setText("親愛的 " + user.getUsername() + ",感謝您的註冊。");
        mailSender.send(msg);
    }
}

進階主題

  • 訊息可靠性:開啟 Publisher Confirms、Consumer 手動 ACK(acknowledge="manual")、佇列與訊息持久化(durable="true")。
  • 死信佇列 (DLX):處理重試失敗的訊息,避免佇列堵塞。
  • 延遲佇列:配合 TTL + DLX 實現定時發送(如 24 小時後發送提醒信)。
  • 序列化:預設使用 Java 序列化,跨語言建議改用 JSON(Jackson2JsonMessageConverter)。

完整專案碼

GitHub:https://github.com/everseeker0307/register

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved