一、异步任务
@Service
public class AsyncService {
@Async //告诉Spring这是一个异步方法
public void hello(){
System.out.println("数据开始处理!");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("数据处理完毕!");
}
}
@RestController
public class AsyncController {
@Autowired
private AsyncService asyncService;
@GetMapping("/hello")
public String hello(){
asyncService.hello();
return "success";
}
}
@EnableAsync //开启异步注解功能
@SpringBootApplication
public class SpringbootTaskApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootTaskApplication.class, args);
}
}
对hello()方法添加@Async
注解可以实现异步方法,前提是需要在主配置类添加注解支持@EnableAsync
。添加注解后,当页面发出请求后,主线程会返回,而内置的线程池会新开线程,在后台执行任务。此时页面不用等待,可以继续其他操作。
默认异步任务线程池
SpringBoot异步任务默认使用的线程池为SimpleAsyncTaskExecutor,其特点如下:
(1)默认定义多少异步任务,创建多少线程(创建线程数量太多,占用内存过大,会造成OutOfMemoryError)。
(2)SimpleAsyncTaskExecutor不提供拒绝策略机制。
(3)SimpleAsyncTaskExecutor可通过设置参数concurrencyLimit(值为大于或等于0的整数),指定启用的线程数目;默认concurrencyLimit取值为-1,即不启用资源节流。
二、定时任务
项目开发中经常需要执行一些定时任务,比如需要在每天凌晨分析一次前一天的日志信息。
Spring为我们提供了异步执行任务调度的方式,提供TaskExecutor
、TaskScheduler
接口。
1、两个注解:@EnableScheduing
、@Scheduled
2、cron表达式
字段 | 允许值 | 允许的特殊字符 |
---|---|---|
秒(Seconds) | 0~59的整数 | , - * / 四个字符 |
分(Minutes) | 0~59的整数 | , - * / 四个字符 |
小时(Hours) | 1~23的整数 | , - * / 四个字符 |
日期(DayofMonth) | 1~31的整数(但是你需要考虑你月的天数) | ,- * ? / L W C 八个字符 |
月份(Month) | 1~12的整数或者 JAN-DEC | , - * / 四个字符 |
星期(DayofWeek) | 1~7的整数或者 SUN-SAT (1=SUN) | , - * ? / L C # 八个字符 |
年(可选,留空)(Year) | 1970~2099 | , - * / 四个字符 |
注,每一个域都使用数字,但还可以出现如下特殊字符,它们的含义是:
(1)*
:表示匹配该域的任意值。假如在Minutes域使用*, 即表示每分钟都会触发事件。
(2)?
:只能用在DayofMonth和DayofWeek两个域。它也匹配域的任意值,但实际不会。因为DayofMonth和DayofWeek会相互影响。例如想在每月的20日触发调度,不管20日到底是星期几,则只能使用如下写法: 13 13 15 20 * ?, 其中最后一位只能用?,而不能使用*,如果使用*表示不管星期几都会触发,实际上并不是这样。
(3)-
:表示范围。例如在Minutes域使用5-20,表示从5分到20分钟每分钟触发一次
(4)/
:表示起始时间开始触发,然后每隔固定时间触发一次。例如在Minutes域使用5/20,则意味着5分钟触发一次,而25,45等分别触发一次.
(5),
:表示列出枚举值。例如:在Minutes域使用5,20,则意味着在5和20分每分钟触发一次。
(6)L
:表示最后,只能出现在DayofWeek和DayofMonth域。如果在DayofWeek域使用5L,意味着在最后的一个星期四触发。
(7)W
:表示有效工作日(周一到周五),只能出现在DayofMonth域,系统将在离指定日期的最近的有效工作日触发事件。例如:在 DayofMonth使用5W,如果5日是星期六,则将在最近的工作日:星期五,即4日触发。如果5日是星期天,则在6日(周一)触发;如果5日在星期一到星期五中的一天,则就在5日触发。另外一点,W的最近寻找不会跨过月份 。
(8)LW
:这两个字符可以连用,表示在某个月最后一个工作日,即最后一个星期五。
(9)#
:用于确定每个月第几个星期几,只能出现在DayofMonth域。例如在4#2,表示某月的第二个星期三。
@Service
public class ScheduledService {
/**
* second,minute,hour,day od mouth,mouth,day of week
* 0 * * * * MON-FRI(共六位用空格隔开)
*/
@Scheduled(cron="0 * * * * MON-FRI")
public void read(){
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式
System.out.println(df.format(new Date())+"read log......");
}
}
@EnableScheduling //开启定时注解功能
@EnableAsync //开启异步注解功能
@SpringBootApplication
public class SpringbootTaskApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootTaskApplication.class, args);
}
}
结果没隔一分钟执行一次:
三、邮件任务
1、邮件发送需要引入spring-boot-starter-mail
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
2、Spring Boot自动配置MailSenderAutoConfiguration
3、定义MailProperties内容,配置在application.yml中
spring.mail.username=发送者邮箱
spring.mail.password=邮箱授权码
spring.mail.host=smtp.qq.com
qq邮箱授权码获取方式:
(1)第一步进入邮箱设置
(2)从设置里进入账户
(3)在账户中开启以下服务:
(4)开启服务后就可以生成授权码了:
spring.mail.host的值:
4、自动装配JavaMailSender
@Autowired
JavaMailSender javaMailSender;
5、测试邮件发送
(1)发送一个简单邮件
@SpringBootTest
class SpringbootTaskApplicationTests {
@Autowired
JavaMailSender javaMailSender;
@Test
void contextLoads() {
//创建一个简单邮件消息
SimpleMailMessage message = new SimpleMailMessage();
//邮件设置
message.setSubject("明天聚餐");
message.setText("时间:2020-11-04 地点:xxx酒店三楼3008包间");
//邮件发给谁
message.setTo("3189434856@qq.com");
//邮件发送者
message.setFrom("1310831650@qq.com");
javaMailSender.send(message);
}
}
发送成功:
(2)发送一个复杂邮件
@SpringBootTest
class SpringbootTaskApplicationTests {
@Autowired
JavaMailSender javaMailSender;
@Test
void sendMail2() throws Exception{
//创建一个复杂的邮件消息
MimeMessage mimeMessage = javaMailSender.createMimeMessage();
//初始化一个helper为MimeMessage设置邮件属性,参数true表示需要上传文件(默认为false)
MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMessage,true);
//邮件设置
mimeMessageHelper.setSubject("科技论坛");
//如果发送的内容为html,需要设置第二个参数为true(默认为false)
mimeMessageHelper.setText("<b style='color:red'>时间:2020-11-05 地点:xxx科技馆2楼205</b>",true);
//邮件发给谁
mimeMessageHelper.setTo("3189434856@qq.com");
//邮件发送者
mimeMessageHelper.setFrom("1310831650@qq.com");
//上传文件
mimeMessageHelper.addAttachment("orange.jpg",new File("C:\\Users\\dell\\Pictures\\MILESupermarket\\orange-super.jpg"));
javaMailSender.send(mimeMessage);
}
}
发送结果: