捕获异常后,方法可以再次调用自身吗?

时间:2019-04-26 14:30:49

标签: java exception javamail

我有一个后台作业正在运行,每天早晨7:00调用一种方法以将电子邮件发送到特定地址,为此我正在使用Java邮件。 我之所以这样问,是因为有时它会发送MessagingException(总是在发生此异常的情况下)。这是错误:

nested exception is:
    class javax.mail.MessagingException: 530 5.7.1 Client was not authenticated

正如我所说,它只是不时发生;但这有点烦人,因为我必须确保手动发送邮件以防失败。我没有找到发生这种情况的原因,我尝试查找此消息,一些答案表明这是服务器出现问题;不幸的是,我无法控制它。当我手动执行例程时,有时最多需要5或7次尝试才能发送邮件。

所以我想做的是在catch部分中调用相同的方法,而且我还放置了一个计数器来控制尝试次数,以防万一异常被捕获超过5次。

您会建议这种方法吗?感谢您的帮助和答复。

这是我每次抛出MessagingException时试图重新调用的方法的代码:

  public void sendMail(String msj, String dest, String asunto, File attachmentSource, int count) {
        String to = dest;
        String from = "some.user@vw.com.mx";
        String host = "someserver.xx.xx.xx";
        boolean debug = true;
        Properties props = new Properties();
        props.put("mail.smtp.host", host);
        if (debug) {
            props.put("mail.debug", "");
        }
        Session session = Session.getInstance(props, null);
        session.setDebug(debug);
        try {
            MimeMessage msg = new MimeMessage(session);
            msg.setFrom(new InternetAddress(from));
            InternetAddress[] address = {new InternetAddress(to)};
            msg.setRecipients(Message.RecipientType.TO, address);
            msg.setSubject("Reporte");
            msg.setSentDate(new Date());
            msg.setText(msj);
            MimeBodyPart messageBodyPart = new MimeBodyPart();
            messageBodyPart.setDataHandler(new DataHandler(new FileDataSource(attachmentSource)));
            messageBodyPart.setFileName(attachmentSource.getName());
            Multipart multipart = new MimeMultipart();
            multipart.addBodyPart(messageBodyPart);
            msg.setContent(multipart);

            Transport.send(msg);
        } catch (MessagingException mex) {
            Logger.getLogger(SendMSG.class.getName()).log(Level.SEVERE, ("ERROR EN ENVÍO!!!! " + mex.getMessage()));
            //THIS IS a TEST TO TRY UNTIL THE MSG IS SENT
            count++;
            if (count <= 5) {
                Logger.getLogger(SendMSG.class.getName()).log(Level.INFO, ("Intento No:  " + count + " de 5" + mex.getMessage()));
                sendMail(msj, dest, asunto, attachmentSource, count);                
            } else {
                Logger.getLogger(SendMSG.class.getName()).log(Level.SEVERE, ("No. de Intentos excedido " + count + " SALIR DE MÉTODO" + mex.getMessage()));
            }
            mex.printStackTrace();
        }
    }

4 个答案:

答案 0 :(得分:3)

您的解决方案很好,但是很混乱。我将重试和发送分开。

public boolean sendMail(String msj, String dest, String asunto, File attachmentSource, int retries) {
    for (int i = 0; i< retries; i++){
        if (sendMail(msj, dest, asunto, attachmentSource)){
            return true;
        }
    }
    return false;
}

public boolean sendMail(String msj, String dest, String asunto, File attachmentSource) {
    try {
        ...
        return true;
    } catch (Exception ex) {
        return false;
    }
}

它的作用与代码基本相同,但提高了可读性。

答案 1 :(得分:0)

想出一种将两件事分开的方法:执行方法的主要逻辑和发生故障时的行为。如果可以编写接口,则可以使用ExceptionHandler的类型,在其中声明方法handleFault(例如)。然后,在您的主类中,您可以注入ExceptionHandler的某些特定实现,以便在发生故障时决定要怎么做。

这将使测试变得更加容易,因为您可以从一个简单的测试对象中替换“实时”或“生产”或我们所谓的行为,而您只想检查是否处理了错误的案例。

我认为值得研究一下马丁·福勒(Martin Fowler)在这里描述的 ciruit断路器模式https://martinfowler.com/bliki/CircuitBreaker.html

您可以有一个单独的策略来处理错误,重试模板(重试次数,两次重试之间的时间等)。

答案 2 :(得分:0)

我想假设错误取决于时间。由于它有时会发生,而有时却不会。考虑到这一点,我建议在count++

之后将wait()放入循环内

像这样:

synchronized (this) 
        {
        this.wait(count*1000);//delay after each error
        }

答案 3 :(得分:0)

其他答案中有一些有用的建议,但是我认为问题的核心部分是您从不对服务器进行身份验证。除非您使用不需要身份验证的本地服务器,否则我不知道它的工作原理。

JavaMail FAQ中所述,将您的Transport.send呼叫替换为

Transport.send(msg, username, password);

用户名和密码是登录邮件服务器的凭据。