How can I separate business logic and email sending functionality?

荒凉一梦 提交于 2019-12-06 08:30:30

What you describe is asynchronous execution and natural way to do async execution is Java is to use threads.

You can introduce some Executor, e.g., Executors.newFixedThreadPool(), and use it to offload mailing task into separate threads.

Aspect itself is a unsuitable place for this, since this would introduce state into aspect, for example, you may want to check if mail task was successful by using returned 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
        }

Better move this logic into separate class and call it from aspect somehow.

You can make the mail sending method @Async. This way Spring will execute this in a seperate thread. Read this blog post about it: Creating Asynchronous Methods

candied_orange

Treat the email sending functionality like an IO device. Make it a plugin to your business logic. Do not allow any knowledge of the fact that you're even talking to the email code into your business logic. Make the email logic depend on the business logic. Never the other way around.

Here's a very good talk about this kind of architecture:

https://vimeo.com/97530863

Here's a series debating it:

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

Here's a ruby master demonstrating it with real code. We miss him.

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

If your business rules are interesting enough to be worth respecting than this is the way to make them the masters of your application. Express them only using java. Don't accept any help. No spring, no weird annotations, just business rules. Push all that "help" out to the mail code.

Do this and your app will scale well. I think this is the best way to put it:

That's from a 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 rounds them up nicely.

Use a localhost MTA (like OpenSMTPD) and then relay to your real SMTP server, like Amazon SES ("Satellite" mode). It won't block.

I did a test, and sent 1000 emails in 2.8 seconds this way

It's simpler than doing async in java, and is useful across multiple applications.

As for separating logic, raise a Spring Application Event when needed, and make another class to listen to it, and send your email from there. Or consider something like Guava's EventBus

Consider creating a separate thread to send emails within your application. This will allow parallel execution(application+email sending).

If you would want another approach you can create a separate back end application that only sends emails. Although you will need to submit the email messages to the application. An asynchronous way to do this is to send a JMS message to the email application.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!