如何分离业务逻辑和电子邮件发送功能?

How can I separate business logic and email sending functionality?

我的 java Web 应用程序有一个要求,我需要在某些情况下发送电子邮件警报。为此,我使用了 javax mail api 并且发送电子邮件效果很好。但问题是程序执行要等到发送电子邮件的方法被执行。由于在各个点要发送数百封电子邮件...这会显着降低性能。

我正在使用spring,也使用过spring aop。谁能建议我如何分离我的业务逻辑和发送电子邮件功能。它应该像 -

发送电子邮件是我的建议,它在调用 xyz 方法时执行 - 因此主执行不应等待建议完成其执行,而应该 return 返回并执行进一步的业务逻辑,因此电子邮件发送单独执行.

这里创建新线程似乎是显而易见的选择。但我认为可能有更好的方法,是吗?谢谢。

考虑在您的应用程序中创建一个单独的线程来发送电子邮件。这将允许并行执行(应用程序+电子邮件发送)。

如果您想要另一种方法,您可以创建一个仅发送电子邮件的单独后端应用程序。尽管您需要将电子邮件消息提交给应用程序。执行此操作的异步方法是向电子邮件应用程序发送 JMS 消息。

将电子邮件发送功能视为 IO 设备。使它成为您业务逻辑的插件。不要让任何人知道您甚至正在与电子邮件代码对话这一事实进入您的业务逻辑。使电子邮件逻辑依赖于业务逻辑。绝不会反过来。

这里有一篇关于这种架构的非常好的演讲:

https://vimeo.com/97530863

这是一系列的辩论:

https://www.youtube.com/watch?v=z9quxZsLcfo

这里有一位 ruby 高手用真实代码演示了它。我们想念他。

https://www.youtube.com/watch?v=tg5RFeSfBM4

如果您的业务规则有趣到值得尊重,那么这就是让它们成为您应用程序的主人的方法。仅使用 java 表达它们。不接受任何帮助。没有 spring,没有奇怪的注释,只有业务规则。将所有 "help" 推送到邮件代码。

这样做,您的应用程序就会很好地扩展。我认为这是最好的表达方式:

这是来自 hexagonal architecture post. But the idea of giving your business rules a safe place to live removed from implementation detail shows up in many architectures. This answer 很好地四舍五入。

您可以设置邮件发送方式@Async。这样 Spring 将在单独的线程中执行。阅读此博客 post:Creating Asynchronous Methods

您描述的是异步执行,进行异步执行的自然方式是 Java 是使用线程。

您可以引入一些 Executor,例如 Executors.newFixedThreadPool(),并使用它来将邮件任务卸载到单独的线程中。

Aspect 本身是一个不合适的地方,因为这会将状态引入 aspect,例如,您可能想通过返回 Future:

来检查邮件任务是否成功
class Mailer {
    private final ExecutorService executor = Executors.newFixedThreadPool(maxMailingThreads);
    //...
        public void doMail(MailTask anEmail) {
            Future<MailTaskResult> future = executor.submit(new MailTask(anEmail));
            future.get().isSuccessful(); // handle success or failure somehow
        }

最好将此逻辑移到单独的 class 中,并以某种方式从方面调用它。

使用本地主机 MTA(如 OpenSMTPD),然后中继到您的真实 SMTP 服务器,如 Amazon SES("Satellite" 模式)。它不会阻塞。

我测试了一下,用这种方法2.8秒发了1000封邮件

它比在 java 中执行异步更简单,并且适用于多个应用程序。

至于分离逻辑,在需要时引发一个 Spring 应用程序事件,并创建另一个 class 来收听它,并从那里发送您的电子邮件。或者考虑类似 Guava 的 EventBus