下面的这个方法是发邮件的抽象出来的一个公用方法:
String[] to 表示收件人列表;
subject 邮件主题;
templateName 邮件末班,用velocity写的,
Map params 参数,用来填充velocity中的某些字段取值的
public void sendHtmlWithTemplate(String[] to, String subject, String templateName, Map<String, Object> params) {
final MimeMessage mimeMessage = mailSender.createMimeMessage();
try {
final MimeMessageHelper messageHelper = new MimeMessageHelper(mimeMessage);
messageHelper.setFrom(simpleMailMessage.getFrom());
if (ENV_ONLINE.equals(environment)) {
messageHelper.setTo(to);
messageHelper.setSubject(subject);
} else {
messageHelper.setTo(adminEmail);
messageHelper.setSubject(subject + Arrays.asList(to));
}
messageHelper.setSentDate(new Date());
final String content = VelocityEngineUtils.mergeTemplateIntoString(velocityEngine, templateName, "UTF-8",
params);
final String[] logTo = to;
messageHelper.setText(content, true);
new Thread() {
@Override
public void run() {
mailSender.send(mimeMessage);
logger.error("Mailsentto: " + Arrays.asList(logTo) + "\nContent: " + content);
}
}.start();
} catch (Exception e) {
logger.error("emailServiceError error:" + e.getMessage(), e);
}
}
在上面的发邮件的代码中,使用了内部类如下:
new Thread() {
@Override
public void run() {
mailSender.send(mimeMessage);
logger.error("Mailsentto: " + Arrays.asList(logTo) + "\nContent: " + content);
}
}.start();
我觉得在这个地方做这个控制是很恰当的吧,为什么team leader让我删掉这个new Thread()的部分。
原话:“把new Thread全部删掉,这些邮件发送不了的bug都没有暴露出来; 邮件发送模块的代码采用异步发送方式,失去异常事务回滚的能力,new Thread要全部删除;” 不懂是什么意思啊?
问题:
1.为什么要去掉new Thread()?
2.在什么样的并发业务场景下,需要使用new Thread()这样的方式?有没有更好的解决方法?
3.在并发场景下,使用new Thread().start()的方式有什么弊端?每次new Thread新建对象性能会很差么?邮件服务也是当触发某个业务规则的时候,可能需要大量发送一下邮件,用线程池好不好呢?
@Youming a déjà évoqué les aspects gênants des cours internes anonymes. Laissez-moi vous l'expliquer en fonction de votre activité :
Selon la logique du code existant, notre service de messagerie devrait exposer la méthode
sendHtmlWithTemplate
au monde extérieur, et nonmailSender.send
, il n'est donc pas nécessaire de réexposer la méthodesendHtmlWithTemplate
à laquelle nous exposons le monde extérieur. Démarrez un fil de discussion pour envoyer des e-mails de manière asynchrone, car pour l'appelant, vous devez en fait lui dire si l'e-mail a été envoyé avec succès cette fois-ci, et s'il a échoué/une exception s'est produite, quelle est la raison de l'échec. Si vous suivez votre plan existant, le monde extérieur peut avoir l'impression que peu importe si l'e-mail est envoyé avec succès ou échoue, le monde extérieur ne le percevra pas, ce qui signifie que l'e-mail ne peut pas être conservé et sera réessayé après un certain temps. . L'envoi d'e-mails de manière asynchrone doit donc être laissé à votre appelant, et non à votre méthodeEn supposant que l'envoi d'e-mails puisse prendre du temps, si nous démarrons un fil de discussion pour chaque e-mail entrant, cela signifie qu'il y aura de nombreux fils de discussion dans le système. Cela signifie qu'il y aura beaucoup de changements de thread, et le changement de thread provoquera un blocage et un réveil. Tout cela implique la conversion du mode utilisateur et du mode noyau ou le changement de contexte de thread, ce qui est très gourmand en CPU et extrême. Dans ce cas, si les threads système ne sont pas accumulés, l'ensemble du service sera DOWN et le service sera dans un état indisponible. new Thread() est en effet une opération très coûteuse
Si vous souhaitez envoyer correctement des e-mails de manière asynchrone, vous devez vraiment le faire dans le pool de threads
Une meilleure façon est d'envoyer des messages électroniques via MQ (considérez les problèmes douloureux courants des messages : 1. Le message sera-t-il perdu ? 2. Que faire si le message est renvoyé), et laissez-le à un serveur séparé Le serveur qui envoie le courrier le fait. Une autre façon consiste à le stocker d'abord dans la table de la base de données. Si l'exigence de rapidité n'est pas très élevée, démarrez un minuteur et envoyez-le lentement.
Les objets anonymes sont très pratiques, mais les objets anonymes sont aussi des démons. S'ils ne sont pas utilisés correctement, votre application s'effondrera. Prenons votre exemple comme exemple. Si vous ne contrôlez pas les paramètres d'envoi des e-mails, par exemple, si vous continuez à attendre après l'expiration du délai d'envoi, ce fil deviendra un fantôme solitaire. Vous ne pourrez pas le trouver ni le fermer. Laissez tomber, est-ce ce qu'un programmeur devrait faire ?
Si vous demandez pourquoi votre tête vous a demandé de supprimer cet endroit, je peux seulement dire qu'il ne fait pas suffisamment confiance à vos capacités, donc il n'ose pas vous laisser contrôler ce diable.
Vous demandez quel scénario est approprié, je peux seulement dire qu'il n'y a pas de scénario approprié, seulement des personnes capables.
Si vous souhaitez envoyer un grand nombre d'e-mails, vous pouvez créer une file d'attente. S'il y a trop de fils de discussion, ce n'est peut-être pas bon.
Désolé, je viens de voir le problème maintenant.
Pour plus de détails, veuillez vous référer aux réponses de @iMouseWu et @有明.
Si vous avez déjà écrit js, vous pouvez comprendre que le
new Thread()
ici est équivalent à la requêteajax
, qui est un comportement asynchrone. Avant que la tâche de thread ne soit terminée, la méthode est revenue à l'appelant (et). non Une exception causée par l'envoi d'e-mails sera levée), c'est ce qu'a dit votre chef "Ces bugs qui ne peuvent pas envoyer d'e-mails ne sont pas exposés" .Si vous considérez que le degré de simultanéité est important, vous pouvez utiliser
redis
+kafka
(ou d'autres composants de message) pour avertir le service de messagerie d'envoyer des e-mails sous forme de messages.