SpringBoot利用线程池实现异步发送邮件
一.前言
1.什么异步
说到什么是异步就要先了解一下和他相对的同步,同步就是指一个接口在调用某个方法的时候,若该方法需要一段时间才能返回信息,那么这个接口会一直的等下去,直到该方法返回信息才能处理下面的逻辑;异步的话就不用等待该方法返回信息,就可以继续处理该接口下面的逻辑。
在这里举个注册发送邮件的例子:
- 同步:
- 异步:
2.使用场景
使用到异步的场景可谓是数不胜数,就比如:
- 注册发送邮件,发送短信
- 定时批处理(比如数据同步)
- 微信消息通知
二.代码实现
1.整合线程池
2.整合邮箱及其工具类
3.实体类
package com.temperature.humidity.system.entity;
import lombok.Data;
/**
* 账户
*/
@Data
public class UserInfo {
/**
* 用户账号
*/
private String username;
/**
* 用户密码
*/
private String password;
/**
* 用户邮箱
*/
private String email;
}
4.Controller层
package com.temperature.humidity.system.controller;
import com.temperature.humidity.system.common.utils.OurMailUtil;
import com.temperature.humidity.system.entity.UserInfo;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.mail.MessagingException;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.Executor;
@RestController
@RequestMapping("/email")
@Log4j2
public class EmailTestController {
/**
* 用于存储用户的信息
* 该Map的key为用户账号,value为用户信息
*/
private static final Map<String, UserInfo> userInfoMap = new LinkedHashMap<>();
/**
* 将mail工具类注入进来
*/
@Autowired
private OurMailUtil ourMailUtil;
/**
* 将线程池注入进来
*/
@Autowired
private Executor threadPoolTaskExecutor;
@PostMapping("/sent")
public String sentEmail(@RequestBody UserInfo userInfo) {
long startTime = System.currentTimeMillis();
try {
//注册用户
userInfoMap.put(userInfo.getUsername(), userInfo);
//要发送人的邮箱
String toEmail = userInfo.getEmail();
//邮箱主题
String subject = "邮箱测试-html";
//邮箱内容
String text = "<p style='color:red'>我是红色</p>";
threadPoolTaskExecutor.execute(() -> {
try {
//调用发送邮件方法
ourMailUtil.sendMailForOnePeople(toEmail, subject, text);
long emailEndTime = System.currentTimeMillis();
log.info("线程{}执行完成,用时{}", Thread.currentThread().getName(), emailEndTime - startTime);
} catch (MessagingException e) {
throw new RuntimeException(e);
}
});
long endTime = System.currentTimeMillis();
log.info("线程{}执行完成,用时{}", Thread.currentThread().getName(), endTime - startTime);
return "用户" + userInfoMap.get(userInfo.getUsername()) + "注册成功";
} catch (RuntimeException e) {
return "注册失败!";
}
}
}
三.测试
我们用Postman传入相应参数发送请求后,返回的结果(出参)如我们所愿。
并且通过下图我们不仅可以看出执行发送邮箱方法的线程并不是主线程而是从线程池中拿的,而且可以通过主线程用时1,而发送邮箱的线程用时3839可以看出我们的发送邮箱方法是异步执行的。