繁体   English   中英

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

[英]Is it ok for a method to call itself again after catching an exception?

我正在运行后台作业,每天早晨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();
        }
    }

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

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;
    }
}

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

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

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

我认为,值得一提的是马丁·福勒(Martin Fowler)在此处描述的电路断路器模式https : //martinfowler.com/bliki/CircuitBreaker.html

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

我想假设错误取决于时间。 由于它有时会发生,而有时却不会。 考虑到这一点,我建议在count++之后将wait()放入循环中

像这样:

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

其他答案中有一些有用的建议,但我认为问题的核心在于您永远不会向服务器进行身份验证。 除非您使用不需要身份验证的本地服务器,否则我不知道它是如何工作的。

JavaMail常见问题解答中所述,将您的Transport.send调用替换为

Transport.send(msg, username, password);

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM