长大后想做什么?做回小孩!

0%

SpringBoot和三种常见任务任务

异步任务、定时任务、邮件任务

异步任务

先模拟一个场景,现在我有一个AsyncService和一个AsyncController:

1
2
3
4
5
6
7
8
9
10
11
@Service
public class AsyncService {
public void hello(){
try {
Thread.sleep(3000);//让方法阻塞三秒
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("处理数据中。。。");
}
}
1
2
3
4
5
6
7
8
9
10
@RestController
public class AsyncController {
@Autowired
AsyncService asyncService;
@RequestMapping("/hello")
public String hello(){
asyncService.hello();
return "success";
}
}

运行该应用并发起请求,在阻塞了三秒之后,控制台打印了“处理数据中。。。”与此同时收到success响应。

上面是个“同步调用”的例子,由于Controller中的hello方法和Service中的hello方法没有必须的依赖关系,所以我们不想让success响应去等待被阻塞的hello方法,那么我们就要让其“异步调用”。在SpringBoot应用中进行异步处理是相对简单的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@EnableAsync//在启动类上开启异步注解功能
@SpringBootApplication
public class TaskTestApplication {
public static void main(String[] args) {
SpringApplication.run(TaskTestApplication.class, args);
}
}

@Service
public class AsyncService {
//@Async标注的方法,称之为异步方法,在执行的时候,spring将会为其开辟独立的线程执行,
//调用者无需等待它的完成,即可继续其他的操作。
@Async
public void hello(){
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("处理数据中。。。");
}
}

重新启动应用并请求,此时success立刻就响应了,经过短暂等待之后控制台上才打印出”处理数据中。。。”,说明现在已经成功进行了”异步调用”了。

*注: *

  1. @Async所修饰的函数不要定义为static类型,这样异步调用不会生效。
  2. 此注解可以用在方法上,也可以用在类上(如果用在类上,这个类中的所有的方法就是异步的)。
  3. 如果需要“异步回调”,可以使用“Future<T>”来返回异步调用的结果。

定时任务

项目开发中经常需要执行一些定时任务,比如需要在每天凌晨时候,分析一次前一天的日志信息。Spring为我们提供了异步执行任务调度的方式,提供TaskExecutor、TaskScheduler接口。

定时任务和上文的异步任务一样便于使用只需要在:启动类上标注@EnableScheduling开启定时任务注解,在需要定时的方方法上标注@Scheduled并写上cron表达式即可。

cron表达式的规则并不复杂,该表达式一共需要六位,每位之间用“空格”隔开,从前往后分别表示“秒,分,小时,日,月,星期”,具体可填写的值见下表:

MOVsFP.png

举几个例子:

  • “0 0 12 * * ?” 每天中午12点触发
  • “0 15 10 ? * *” 每天上午10:15触发
  • “0 15 10 * * ?” 每天上午10:15触发
  • “0 15 10 * * ? *” 每天上午10:15触发
  • “0 15 10 * * ? 2005” 2005年的每天上午10:15触发
  • “0 * 14 * * ?” 在每天下午2点到下午2:59期间的每1分钟触发
  • “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 15 * ?” 每月15日上午10:15触发
  • “0 15 10 L * ?” 每月最后一日的上午10:15触发
  • “0 15 10 ? * 6L” 每月的最后一个星期五上午10:15触发
  • “0 15 10 ? * 6L 2002-2005” 2002年至2005年的每月的最后一个星期五上午10:15触发
  • “0 15 10 ? * 6#3” 每月的第三个星期五上午10:15触发
1
2
3
4
5
6
7
8
@EnableScheduling//开启定时任务
@EnableAsync
@SpringBootApplication
public class TaskTestApplication {
public static void main(String[] args) {
SpringApplication.run(TaskTestApplication.class, args);
}
}
1
2
3
4
5
6
7
8
@Service
public class ScheduleService {
// 每天每分钟1至30秒每秒执行
@Scheduled(cron = "1-30 * * * * *")
public void demo(){
System.out.println("demo....");
}
}

@Scheduled注解有多个属性:

  • @Scheduled(fixedRate = 5000) :上一次开始执行时间点之后5秒再执行
  • @Scheduled(fixedDelay = 5000) :上一次执行完毕时间点之后5秒再执行
  • @Scheduled(initialDelay=1000, fixedRate=5000) :第一次延迟1秒后执行,之后按fixedRate的规则每5秒执行一次
  • @Scheduled(cron="*/5 * * * * *") :通过cron表达式定义规则

邮件任务

既然是邮件任务,那么必须要引入邮件发送的依赖和相关配置:

1
2
3
4
5
6
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-mail -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
<version>2.2.0.RELEASE</version>
</dependency>
1
2
3
4
5
6
7
8
#邮箱账户
spring.mail.username=577373789@qq.com
#在邮箱设置界面开启SMTP服务并生成授权码
spring.mail.password=xzodfhcfmzaebbfi
#在邮箱设置界面查看发送邮件的服务器
spring.mail.host=smtp.qq.com
#QQ邮箱需要开启SSL,来保证安全
spring.mail.properties.mail.smtp.ssl.enable=true

测试一下是否可以发送简单邮件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Autowired
JavaMailSenderImpl mailSender;

@Test
void contextLoads() {
// 创建一个简单邮件信息
SimpleMailMessage simpleMailMessage=new SimpleMailMessage();
// 设置邮件标题
simpleMailMessage.setSubject("lmh");
// 设置邮件内容
simpleMailMessage.setText("111111111");
// 设置邮件目标
simpleMailMessage.setTo("2818553826@qq.com");
// 设置邮件来源
simpleMailMessage.setFrom("577373789@qq.com");
// 发送邮件
mailSender.send(simpleMailMessage);
}

运行后发现目标邮箱中收到了该邮件,接下来测试发送一个稍微复杂的邮件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Autowired
JavaMailSenderImpl mailSender;
@Test
public void test02() throws Exception {
// 创建一个复杂邮件信息
MimeMessage message = mailSender.createMimeMessage();
// 如果需要上传文件,就将第二个multiple参数设为true
MimeMessageHelper helper=new MimeMessageHelper(message,true);
// 邮件设置
helper.setSubject("lmh");
// 如果需要将内容当做HTML,则需要将第二个参数设置为true
helper.setText("<font color=red>111111111</font>",true);
helper.setTo("2818553826@qq.com");
helper.setFrom("577373789@qq.com");
// 上传文件
helper.addAttachment("图片1",new File("E:\\images\\83394.jpg"));
helper.addAttachment("图片2",new File("E:\\images\\83395.jpg"));
// 最后别忘了发送
mailSender.send(message);
}

也没什么问题成功接收到邮件,邮件内容为红色字体,并且有两个附件。