SpringBoot - 异步任务、邮件发送、定时任务
一、异步任务
1)什么是异步调用?
异步调用是相对于同步调用而言的,同步调用是指程序按预定顺序一步步执行,每一步必须等到上一步执行完后才能执行,异步调用则无需等待上一步程序执行完即可执行。
2)如何实现异步调用?
多线程,这是很多人第一眼想到的关键词,没错,多线程就是一种实现异步调用的方式。
在非 Spring 目项目中我们要实现异步调用的就是使用多线程方式,可以自己实现 Runable 接口或者集成 Thread 类,或者使用 jdk1.5 以上提供了的 Executors 线程池。
StrngBoot中 则提供了很方便的方式执行异步调用。
3)异步接口的使用场景
耗时比较长,任务比较多的接口。比方说,文件下载,大文件下载比较耗时,这个时候就可以使用异步接口。
4)实例
SpringBoot依赖:
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.6.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
@EnableAsync:在Application启动类中添加@EnableAsync注解
@SpringBootApplication @EnableAsync // 开启异步注解功能 public class Spring09TestApplication { public static void main(String[] args) { SpringApplication.run(Spring09TestApplication.class, args); } }
@Async:表示这是一个异步的方法。
@Service public class AsyncService { @Async // 表示这是一个异步方法 public void hello() { try { Thread.sleep(7000); //睡眠7秒 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("数据正在处理......"); } }
测试:
@RestController public class AsyncController { @Autowired AsyncService asyncService; @RequestMapping("/hello") public String hello(){ asyncService.hello(); // 停止七秒 return "OK"; } }

测试立刻访问到了,OK。
如果是非异步的话,就会出现令人非常不爽的转圈圈,访问的时候需要等待service的方法在睡眠中醒来才能访问到OK。

二、邮件发送
SpringBoot 实现邮件功能是非常的方便快捷的,因为 SpringBoot 默认有 starter 实现了 Mail 。发送邮件应该是网站的必备功能之一,什么注册验证,忘记密码或者是给用户发送营销信息。最早期的时候我们会使用 JavaMail 相关 api 来写发送邮件的相关代码,后来 spring 推出了 JavaMailSender 更加简化了邮件发送的过程,在之后 springboot 对此进行了封装就有了现在的 spring-boot-starter-mail。
下面就开始使用 SpringBoot 的邮件发送。
1)基础配置
● 引入依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
● 获取邮箱授权码 - 这里使用QQ邮箱
QQ邮箱 -> 设置 -> 账户 -> POP3/SMTP服务:开启服务后会获得QQ的授权码.
● Mail配置文件
host:邮箱服务器地址:这里根据自己的情况填写
- QQ:smtp.qq.com
- sina:smtp.sina.cn
- aliyun:smtp.aliyun.com
- 163:smtp.163.com
spring: mail: #邮箱配置 host: smtp.foxmail.com # 邮箱服务器地址 username: cyan9207@foxmail.com # 邮箱用户名 password: yslnzsijsxfdbeab # 授权码 default-encoding: UTF-8 # 编码格式 properties: mail: smtp: auth: true starttls: enable: true required: true #设置一个邮件发送人 lance: mail: sender: cyan9207@foxmail.com
2)Conroller测试邮箱发送
package com.cyan.controller; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.core.io.FileSystemResource; import org.springframework.mail.SimpleMailMessage; import org.springframework.mail.javamail.JavaMailSender; import org.springframework.mail.javamail.MimeMessageHelper; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.mail.MessagingException; import javax.mail.internet.MimeMessage; import java.io.File; @RestController public class MailController { @Value("${lance.mail.sender}") private String sender; // 邮件发送人 @Autowired private JavaMailSender javaMailSender; /* * * @Description http://localhost:8080/sendMail * @method 发送文本邮件 */ @RequestMapping("/sendMail") public String sendMail() { SimpleMailMessage message = new SimpleMailMessage(); //邮件发送人 message.setFrom(sender); //邮件接收人 message.setTo("870919701@qq.com"); //邮件主题 message.setSubject("Cyan"); // 邮件内容 message.setText("Hello!!!Hello!!!Hello!!!"); try { javaMailSender.send(message); System.err.println("简单邮件已经发送"); } catch (Exception e) { System.err.println("发送简单邮件时发生异常!===>" + e.getMessage()); } return "success"; } /* * * @Description http://localhost:8080/sendHtmlMail * @method 发送Html邮件 */ @RequestMapping("/sendHtmlMail") public String testHtmlMail() { String content="<html>\n" + "<body>\n" + "<h3>hello world ! 这是一封Html邮件!</h3>\n" + "</body>\n" + "</html>"; MimeMessage message = javaMailSender.createMimeMessage(); try { // true表示需要创建一个multipart message MimeMessageHelper helper = new MimeMessageHelper(message, true); // 邮件发送人 helper.setFrom(sender); // 邮件接收人 helper.setTo("870919701@qq.com"); // 邮件主题 helper.setSubject("html mail"); // 邮件内容 helper.setText(content, true); javaMailSender.send(message); System.err.println("html邮件发送成功"); } catch (MessagingException e) { System.err.println("发送html邮件时发生异常!" + e); } return "success"; } /* * * @Description http://localhost:8080/sendFilesMail * @method 发送附件邮件 */ @RequestMapping("/sendFilesMail") public String sendFilesMail() { MimeMessage message = javaMailSender.createMimeMessage(); try { MimeMessageHelper helper = new MimeMessageHelper(message, true); // 邮件发送人 helper.setFrom(sender); // 邮件接收人 helper.setTo("870919701@qq.com"); // 邮件主题 helper.setSubject("附件邮件"); // 邮件内容 helper.setText("这是一封带附件的邮件", true); FileSystemResource file = new FileSystemResource(new File("C:\\Users\\ASUS\\Desktop\\JVM.txt")); helper.addAttachment(file.getFilename(), file); javaMailSender.send(message); System.err.println("带附件的邮件已经发送。"); } catch (MessagingException e) { System.err.println("发送带附件的邮件时发生异常! " + e); } return "success"; } /* * * @Description http://localhost:8080/sendInlineResourceMail * @method 发送图片邮件 */ @RequestMapping("/sendInlineResourceMail") public String sendInlineResourceMail() { String Id = "Cyan-"; String content="<html><body>这是有图片的邮件:<img src=\'cid:" + Id + "\' ></body></html>"; String imgPath = "C:\\Users\\ASUS\\Pictures\\壁纸\\MK47.jpg"; MimeMessage message = javaMailSender.createMimeMessage(); try { MimeMessageHelper helper = new MimeMessageHelper(message, true); // 邮件发送人 helper.setFrom(sender); // 邮件接收人 helper.setTo("870919701@qq.com"); // 邮件主题 helper.setSubject("这是有图片的邮件"); // 邮件内容 helper.setText(content, true); FileSystemResource res = new FileSystemResource(new File(imgPath)); helper.addInline(Id, res); javaMailSender.send(message); System.err.println("嵌入静态资源的邮件已经发送。"); } catch (MessagingException e) { System.err.println("发送嵌入静态资源的邮件时发生异常!" + e); } return "success"; } }
① 发送简单的文本邮件
@RequestMapping("/sendMail")
public String sendMail() {
SimpleMailMessage message = new SimpleMailMessage();
//邮件发送人
message.setFrom(sender);
//邮件接收人
message.setTo("870919701@qq.com");
//邮件主题
message.setSubject("Cyan");
// 邮件内容
message.setText("Hello!!!Hello!!!Hello!!!");
try {
javaMailSender.send(message);
System.err.println("简单邮件已经发送");
} catch (Exception e) {
System.err.println("发送简单邮件时发生异常!===>" + e.getMessage());
}
return "success";
}
访问:localhost:8080/sendMail

控制台:

邮箱接收:

② 发送html邮件
@RequestMapping("/sendHtmlMail")
public String testHtmlMail() {
String content="<html>\n" +
"<body>\n" +
"<h3>hello world ! 这是一封Html邮件!</h3>\n" +
"</body>\n" +
"</html>";
MimeMessage message = javaMailSender.createMimeMessage();
try {
// true表示需要创建一个multipart message
MimeMessageHelper helper = new MimeMessageHelper(message, true);
// 邮件发送人
helper.setFrom(sender);
// 邮件接收人
helper.setTo("870919701@qq.com");
// 邮件主题
helper.setSubject("html mail");
// 邮件内容
helper.setText(content, true);
javaMailSender.send(message);
System.err.println("html邮件发送成功");
} catch (MessagingException e) {
System.err.println("发送html邮件时发生异常!" + e);
}
return "success";
}
访问:localhost:8080/sendHtmlMail

控制台:

邮箱接收:

③ 发送附件邮件
@RequestMapping("/sendFilesMail")
public String sendFilesMail() {
MimeMessage message = javaMailSender.createMimeMessage();
try {
MimeMessageHelper helper = new MimeMessageHelper(message, true);
// 邮件发送人
helper.setFrom(sender);
// 邮件接收人
helper.setTo("870919701@qq.com");
// 邮件主题
helper.setSubject("附件邮件");
// 邮件内容
helper.setText("这是一封带附件的邮件", true);
FileSystemResource file = new FileSystemResource(new File("C:\\Users\\ASUS\\Desktop\\JVM.txt"));
helper.addAttachment(file.getFilename(), file);
javaMailSender.send(message);
System.err.println("带附件的邮件已经发送。");
} catch (MessagingException e) {
System.err.println("发送带附件的邮件时发生异常! " + e);
}
return "success";
}
访问:localhost:8080/sendFilesMail

控制台:

邮箱接收:

④ 发送图片邮件
@RequestMapping("/sendInlineResourceMail")
public String sendInlineResourceMail() {
String Id = "Cyan-";
String content="<html>" +
"<body>这是有图片的邮件:<img src=\'cid:" + Id + "\' ></body>" +
"</html>";
String imgPath = "C:\\Users\\ASUS\\Pictures\\壁纸\\MK47.jpg";
MimeMessage message = javaMailSender.createMimeMessage();
try {
MimeMessageHelper helper = new MimeMessageHelper(message, true);
// 邮件发送人
helper.setFrom(sender);
// 邮件接收人
helper.setTo("870919701@qq.com");
// 邮件主题
helper.setSubject("这是有图片的邮件");
// 邮件内容
helper.setText(content, true);
FileSystemResource res = new FileSystemResource(new File(imgPath));
helper.addInline(Id, res);
javaMailSender.send(message);
System.err.println("嵌入静态资源的邮件已经发送。");
} catch (MessagingException e) {
System.err.println("发送嵌入静态资源的邮件时发生异常!" + e);
}
return "success";
}
访问:localhost:8080/sendInlineResourceMail

控制台:

邮箱接收:

三、定时任务
项目开发中经常需要执行一些定时任务,比如需要在每天凌晨时候,分析一次前一天的日志信息。Spring为我们提供了异步执行任务调度的方式,提供TaskExecutor 、TaskScheduler 接口。
在SpringBoot如何使用呢?
@EnableScheduling:在主方法中开启支持注解的定时任务
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.scheduling.annotation.EnableScheduling; @SpringBootApplication @EnableScheduling // 开启定时任务功能 public class Spring09TestApplication { public static void main(String[] args) { SpringApplication.run(Spring09TestApplication.class, args); } }
@Scheduled:在要定时的方法上增加注解@Scheduled(cron = "秒 分 时 日 月 周几")
import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; import java.util.Date; @Service public class ScheduledService { @Scheduled(cron = "0/2 * * * * ?") // 每隔2秒执行一次 public void test(){ System.err.println(new Date()); } }
启动Application测试:每两秒执行一次

Cron表达式
cron计划任务,是任务在约定的时间执行已经计划好的工作。在Linux中,我们经常用到 cron 服务器来完成这项工作。cron服务器可以根据配置文件约定的时间来执行特定的任务。
● * :表示匹配该域的任意值,假如在Minutes域使用*, 即表示每分钟都会触发事件。
● ? :只能用在DayofMonth和DayofWeek两个域。它也匹配域的任意值,但实际不会。因为DayofMonth和DayofWeek会相互影响。例如想在每月的20日触发调度,不管20日到底是星期几,则只能使用如下写法: 13 13 15 20 * ?, 其中最后一位只能用?,而不能使用,如果使用表示不管星期几都会触发,实际上并不是这样。
● - :表示范围,例如在Minutes域使用5-20,表示从5分到20分钟每分钟触发一次
● / :表示起始时间开始触发,然后每隔固定时间触发一次,例如在Minutes域使用5/20,则意味着5分钟触发一次,而25,45等分别触发一次.
● , :表示列出枚举值值。例如:在Minutes域使用5,20,则意味着在第5和第20分钟分别触发一次。
● L :表示最后,只能出现在DayofWeek和DayofMonth域,如果在DayofWeek域使用5L,意味着在最后的一个星期四触发。
举例:
( 0 0 2 1 * ? * ):表示在每月的1日的凌晨2点调度任务
( 0 15 10 ? * MON-FRI ):表示周一到周五每天上午10:15执行作业
( 0 15 10 ? * 6L 2020-2022 ) :表示2020-2022年的每个月的最后一个星期五上午10:15执行作
( 0 0 10,14,16 * * ? ) :每天上午10点,下午2点,4点
( 0 0/30 9-17 * * ? ) :朝九晚五工作时间内每半小时
( 0 0 12 ? * WED ) :表示每个星期三中午12点
( 0 0 12 * * ? ) :每天中午12点触发
( 0 15 10 * * ? 2020 ) :2020年的每天上午10:15触发
( 0 0/5 14 * * ? ) :在每天下午2点到下午2:55期间的每5分钟触发
( 0 0/5 14,18 * * ? ) :在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发
( 0 0-5 14 * * ? ) :在每天下午2点到下午2:05期间的每1分钟触发
( 0 10,44 14 ? 3 WED ) :每年三月的星期三的下午2:10和2:44触发
( 0 15 10 ? MON-FRI ) :周一至周五的上午10:15触发
( 0 15 10 L * ? ) :每月最后一日的上午10:15触发
( 0 15 10 ? * 6L ) :每月的最后一个星期五上午10:15触发
( 0 15 10 ? * 6L 2020-2022) :2020年至2022年的每月的最后一个星期五上午10:15触发

浙公网安备 33010602011771号