使用 Javamail 发送电子邮件的 Quartz 作业,但 Javamail 是同步的

Quartz job to send email using Javamail, but Javamail is synchronous

标题基本上概括了我目前的问题。如果我同时有作业 运行ning at/around 的多个实例,Javamail 会抛出异常,因为它应该被同步使用。有什么方法可以使它异步 运行 吗?或者是否有异步的 Javamail 替代方案?

我认为有几种方法可以处理此类任务:

  1. 封装成一个服务,然后定期发送一批电子邮件;
  2. 在线程中发送每封电子邮件,即暗示单独的 SMTP 连接;

    @Async
    public void sendEmail(String smtpServer, String to,String from,String subject, String body) {
          send(smtpServer, to, from, subject, body);
    }
    

我一直在用 Quartz 做这种事情。您需要做的就是分拆另一个线程。你如何做到这一点在很大程度上取决于你的环境。您 运行 在应用程序服务器上还是只是 运行 香草 Java?

如果是后者,那么您只需分拆一个线程,并且有很多关于它的教程。

如果您 运行 在像 Wildfly 这样的应用服务器上,请在会话 bean 上使用 @Asynchronous 标记。唯一棘手的一点是您不能将 CDI 插入到 Quartz 调度作业中,因此您将需要使用 JNDI 来获取所需会话 bean 的容器代理。像这样:

    @NoArgsConstructor
    @ApplicationScoped
    @Slf4j
    public class YourJob implements Job {


    public void execute(JobExecutionContext context) throws JobExecutionException      
{
    String message = "";
    try {
        final InitialContext ctx = new InitialContext();
        final IYourSessionBean yoruSessionBean = (IYourSessionBean) ctx.lookup("java:global/server-core/YourSessionBean!com.somecompany.interfaces.IYourSessionBean");

        final JobKey key = context.getJobDetail().getKey();      
        final JobDataMap dataMap = context.getJobDetail().getJobDataMap();      

        String taskID   = dataMap.getString(BjondQuartzService.TASKID);      
        String descr    = dataMap.getString(BjondQuartzService.DESCRIPTION);

        yourSessionBean.assignTaskAsync(taskID, descr);

        context.setResult("SUCCESS");
    } catch(Exception e) {
        log.error("Could not assign task: {}", message, e);
        context.setResult("FAILURE");
    }
}      

}

然后在接收端:

@Asynchronous
@TransactionAttribute(REQUIRED)
@Override
public void assignTaskAsync(@NotNull(message="taskID must not be null")
                            final String taskID,
                            @NotNull(message="descr must not be null")
                            final String descr
                            ) throws Exception {

      Do some stuff here.
}

注意@Asychronous 标记。每个容器都有许多可用的线程,这些线程可以并且将从池中提取并用于像这样的异步调用。我发现这比直接处理 Runnable 更容易。