用戶註冊後,需發送歡迎郵件。為了不阻塞主流程、提升響應速度,採用「生產者寫入隊列、消費者異步發送」架構:
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-rabbit</artifactId>
<version>1.6.0.RELEASE</version>
</dependency>
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>1.4.7</version>
</dependency>
<beans xmlns="https://www.springframework.org/schema/rabbit"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
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="admin" password="123456" />
<!-- 管理 Queue/Exchange/Binding -->
<admin connection-factory="connectionFactory" />
<queue id="emailQueue" name="user.register.email" durable="true" />
<direct-exchange name="user.register.exchange" durable="true">
<bindings>
<binding queue="emailQueue" /> <!-- routing key 默認等於 queue name -->
</bindings>
</direct-exchange>
<!-- RabbitTemplate 發送 -->
<template id="rabbitTemplate" connection-factory="connectionFactory" />
<!-- 監聽器容器 + 消費者 -->
<bean id="emailHandler" class="com.example.EmailHandler" />
<listener-container connection-factory="connectionFactory" acknowledge="auto">
<listener ref="emailHandler" method="handle" queue-names="user.register.email" />
</listener-container>
</beans>
默認 guest/guest 僅允許 localhost。生產環境需:
https://host:15672) → Admin → Users → Add user (administrator)。@Service
public class UserAlertServiceImpl implements UserAlertService {
private final RabbitTemplate rabbitTemplate;
public UserAlertServiceImpl(RabbitTemplate rabbitTemplate) { this.rabbitTemplate = rabbitTemplate; }
@Override
public void sendRegisterEmail(User user) {
// convertAndSend 自動序列化對象為 Message
rabbitTemplate.convertAndSend("user.register.exchange", "user.register.email", user);
}
}
@Component
public class EmailHandler {
private final UserMailService mailService;
public EmailHandler(UserMailService mailService) { this.mailService = mailService; }
public void handle(User user) {
mailService.sendWelcomeMail(user.getEmail(), user);
}
}
@Bean
public JavaMailSenderImpl 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 配置 (QQ/GMail/163 SSL)
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;
public UserMailServiceImpl(MailSender mailSender) { this.mailSender = mailSender; }
@Override
public void sendWelcomeMail(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);
}
}
durable="true" 確保 Queue/Exchange 重啟不丟失;消息發送端亦需 MessageDeliveryMode.PERSISTENT (Spring AMQP 默認)。acknowledge="auto" 消費者成功處理自動 ack,異常則重回隊列。Serializable,字段含非序列化對象需 transient。RetryTemplate 或死信隊列 (DLX) 進一步保障。spring-boot-starter-amqp 簡化配置 (YAML)。@RabbitListener 註解替代 XML 監聽器定義。spring-retry 實現指數退避重試。通過 RabbitMQ 解耦「業務寫入」與「郵件發送」,系統吞吐量與穩定性顯著提升,是微服務架構中常見的異步處理模式。