如何使用spring 4 @Async异步发送电子邮件

时间:2015-07-02 10:18:44

标签: java-8 spring-4

我知道已经问过这个问题,但我无法使用配置发送电子邮件。我不知道我做错了什么,为什么我没有收到电子邮件。这是我的Spring配置。

@Configuration
@PropertySource(value = { 
    "classpath:autoalert.properties"
})
@EnableAsync
@Import({PersistenceConfig.class, EmailConfig.class, VelocityConfig.class})
@ComponentScan(basePackageClasses = { 
    ServiceMarker.class,
    RepositoryMarker.class }
)
public class AutoAlertAppConfig {

    @Bean
    public static PropertySourcesPlaceholderConfigurer propertyConfigInDev() {
        return new PropertySourcesPlaceholderConfigurer();
    }
}

这是我的电子邮件配置

@Configuration
@PropertySources({
@PropertySource("classpath:email/email.properties")
})
public class EmailConfig {

    @Autowired
    private Environment env;

    @Bean
    public JavaMailSender mailSender() {
         JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
         mailSender.setSession(getEmailSession());
         return mailSender;
     }

     @Bean
     public MailMessage mailSettings() {
         SimpleMailMessage mailMessage = new SimpleMailMessage();
         mailMessage.setFrom(env.getProperty("mail.from"));
         ...
         mailMessage.setText(env.getProperty("mail.body"));
         return mailMessage;
     }

    private Session getEmailSession() {

         Properties emailProperties = SpringUtil.loadPropertiesFileFromClassPath("email" + File.separator + "general-mail-settings.properties");

         final String userName = emailProperties.getProperty("user");
         final String password = emailProperties.getProperty("password");

        Session session = null;
        try {

            session = Session.getInstance(emailProperties, new javax.mail.Authenticator() {
            protected PasswordAuthentication getPasswordAuthentication() {
                    return new PasswordAuthentication(userName, password);      
                }       
            });  //end of anonymous class       
        } catch (Exception e) {
            e.printStackTrace();
        }
        return session;

    } //end of getEmailSession()

}

这是我的班级

public static void main(String[] args) { 

    try (GenericApplicationContext springContext = new AnnotationConfigApplicationContext(AutoAlertAppConfig.class)) {
        AutoAlertService autoAlertService = springContext.getBean(AutoAlertServiceImpl.class);
        try {
            autoAlertService.handleProcess(fromDate, toDate);
        } catch (Exception e) {
            logger.error("Exception occurs", e);
            autoAlertService.handleException(fromDate, toDate, e);
        }
    } catch (Exception e) {
        logger.error("Exception occurs in loading Spring context: ", e);
    }

@Service
public class AutoAlertServiceImpl implements AutoAlertService {

    @Inject
    private AsyncEmailService asyncEmailService;

    @Override
    public void handleProcess(String fromDate, String toDate) {
        logger.info("Start process");
        try {
            ..
            //Sending email 
            asyncEmailService.sendMailWithFileAttachment(fromDate, toDate, file);
        } catch (Exception e) {
            handleException(fromDate, toDate, e);
        }
        logger.info("Finish process");
    }
}

这是我的电子邮件服务

@Component
public class AsyncEmailServiceImpl implements AsyncEmailService {

    @Resource(name="mailSender")
    private JavaMailSender mailSender;

    @Resource(name="mailSettings")
    private SimpleMailMessage simpleMailMessage;

    @Async
    @Override
    public void sendMailWithFileAttachment(String from, String to, String attachFile) {
        logger.info("Start execution of async. Sending email with file attachment");
        MimeMessage message = mailSender.createMimeMessage();
        try{
            MimeMessageHelper helper = new MimeMessageHelper(message, true);
            ....
            helper.setText(String.format(simpleMailMessage.getText(), from, to));
            FileSystemResource file = new FileSystemResource(attachFile);
            helper.addAttachment(file.getFilename(), file);
            mailSender.send(message);
        } catch (MessagingException e) {
            logger.error("Exception occurs in sending email with file attachment: " + attachFile, e);
            throw new MailParseException(e);
        }
        logger.info("Complete execution of async. Email with file attachment " + attachFile + " send successfully.");

    }
}

当我运行代码时,它来到方法。这打印在控制台上

13:59:43.004 [main] INFO  com.softech.vu360.autoalert.service.impl.AutoAlertServiceImpl - Finish process
13:59:43.005 [SimpleAsyncTaskExecutor-1] INFO  com.softech.vu360.autoalert.service.impl.AsyncEmailServiceImpl - Start execution of async. Sending email with file attachment
13:59:43.007 [main] INFO  com.softech.vu360.autoalert.AutoAlert - Exiting application.

但我没有收到任何电子邮件。在同步通话的情况下,我收到了电子邮件。为什么我没有收到电子邮件?我做错了吗?

由于

1 个答案:

答案 0 :(得分:2)

我认为这是更好的方法。创建一个文件AsyncConfig.java

@Configuration
@EnableAsync(proxyTargetClass = true)
@EnableScheduling
public class AsyncConfig implements SchedulingConfigurer, AsyncConfigurer {

    private static final Logger log = LogManager.getLogger();
    private static final Logger schedulingLogger = LogManager.getLogger(log.getName() + ".[scheduling]");

    @Bean
    public ThreadPoolTaskScheduler taskScheduler() {

        log.info("Setting up thread pool task scheduler with 20 threads.");
        ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
        scheduler.setPoolSize(2);
        scheduler.setThreadNamePrefix("task-");
        scheduler.setAwaitTerminationSeconds(1200);  // 20 minutes
        scheduler.setWaitForTasksToCompleteOnShutdown(true);
        scheduler.setErrorHandler(t -> schedulingLogger.error("Unknown error occurred while executing task.", t));
        scheduler.setRejectedExecutionHandler((r, e) -> schedulingLogger.error("Execution of task {} was rejected for unknown reasons.", r));
        return scheduler;
    }

    @Override
    public Executor getAsyncExecutor() {
        Executor executor = this.taskScheduler();
        log.info("Configuring asynchronous method executor {}.", executor);
        return executor;
    }

    @Override
    public void configureTasks(ScheduledTaskRegistrar registrar) {
        TaskScheduler scheduler = this.taskScheduler();
        log.info("Configuring scheduled method executor {}.", scheduler);
        registrar.setTaskScheduler(scheduler);
    }

    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return new SimpleAsyncUncaughtExceptionHandler();
    }
}

现在将其导入您的主配置

@Configuration
@PropertySource(value = { 
    "classpath:autoalert.properties"
})
@Import({AsyncConfig.class, PersistenceConfig.class, EmailConfig.class, VelocityConfig.class})
@ComponentScan(basePackageClasses = { 
    ServiceMarker.class,
    RepositoryMarker.class }
)
public class AutoAlertAppConfig {

    @Bean
    public static PropertySourcesPlaceholderConfigurer propertyConfigInDev() {
        return new PropertySourcesPlaceholderConfigurer();
    }
}

将返回类型从void更改为Future

@Service
public class AsyncEmailServiceImpl implements AsyncEmailService {

    @Resource(name="mailSender")
    private JavaMailSender mailSender;

    @Resource(name="mailSettings")
    private SimpleMailMessage simpleMailMessage;

    @Async
    @Override
    public Future<String> sendMailWithFileAttachment(String from, String to, String attachFile) {
        ....
         return new AsyncResult<String>("Attachment File successfully send: " + attachFile);
    }

    @Async
    @Override
    public Future<String> sendMail(String from, String to, String emailBody) {
        ....
        return new AsyncResult<String>("Email send successfully");
    }
}

并在我的服务类中执行此操作

logger.info("Start process");
try {
    ....
    //Sending email 
    Future<String> result  = asyncEmailService.sendMailWithFileAttachment(fromDate, toDate, file);
} catch (Exception e) {
    handleException(fromDate, toDate, e);
}
logger.info("Finish process");

请勿查看result.get()。现在当新线程启动并且应用程序开始完成时。我在scheduler.setAwaitTerminationSeconds(1200); // 20 minutes中配置了AsyncConfig.java。这将确保在应用程序关闭之前必须完成所有挂起的线程。当然,这可以根据任何需要进行改变。 现在,当我运行应用程序时,它会在控制台上打印这些

12:55:33.879 [main] INFO  com.softech.vu360.autoalert.service.impl.AutoAlertServiceImpl - Finish process
12:55:33.895 [task-1] INFO  com.softech.vu360.autoalert.service.impl.AsyncEmailServiceImpl - Start execution of async. Sending email with file attachment
12:58:09.030 [task-1] INFO  com.softech.vu360.autoalert.service.impl.AsyncEmailServiceImpl - Complete execution of async. Email with file attachment D:\projects\AutoAlerts\marketo\autoalert 2015-08-24 to 2015-08-30.csv send successfully.
12:58:09.033 [main] INFO  com.softech.vu360.autoalert.AutoAlert - Exiting application.

请参阅启动新线程,但在应用程序关闭之前确保,线程完成然后退出应用程序。我为电子邮件配置了20分钟,但是一旦线程完成,应用程序就会关闭。这是幸福的结局:)