在Java应用中绝大多数情况下默认都是通过同步的方式来实现交互处理的
但在处理与第三方系统交互的时候 容易造成响应迟缓的情况
可以使用多线程来完成此类任务 但其实 在Spring 3.x之后 已经内置了@Async
注解来完美解决该问题
首先来模拟一个同步任务响应迟缓的场景 以供比较:
Service:
@Service
public class AsyncService {
public void hello()
{
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Hello");
}
}
Controller:
@RestController
public class AsyncController {
@Autowired
AsyncService asyncService;
@GetMapping("/hello")
public String hello()
{
asyncService.hello();
return "success";
}
}
此时 若访问/hello 则需要先等待两秒才可在页面显示出"success"结果 控制台打印"Hello"字样
开启异步任务:在主程序类上添加@EnableAsync
注解来开启异步注解功能:
@SpringBootApplication
@EnableAsync // 开启异步注解功能
public class SpringbootTaskApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootTaskApplication.class, args);
}
}
然后 给要进行异步任务的方法上添加@Async
注解即可:
添加该注解之后 Spring就会自动开启一个线程池进行调用
@Service
public class AsyncService {
// 用@Async注解来说明这是一个异步方法
@Async
public void hello()
{
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Hello");
}
}
此时 若访问/hello 直接可在页面显示出"success"结果 然后等待两秒后在控制台打印"Hello"字样 实现了异步
二、定时任务在项目开发中经常需要执行一些定时的任务
例如 在每天凌晨时候分析一次前一天的日志信息
Spring提供了异步执行任务调度的方式 提供了两个注解:@EnableScheduling
和@Scheduled
定时任务使用cron表达式来指定定时的时间
cron表达式:
星期可以用英文前三位 或是数字
用数字的时候 1-6代表周一到周六 0和7都可代表周日
枚举:
例:0,1,2,3,4 * * * * MON-SAT
意为:周一到周六无论什么时候 每当处在0,1,2,3,4秒时 运行一次
区间:
例:0-4 * * * * MON-SAT
意为:周一到周六无论什么时候 每当处在0,1,2,3,4秒时 运行一次
步长:
指定每隔多长时间执行一次
例:0/4 * * * * MON-SAT
意为:周一到周六无论什么时候 从0秒开始启动 每隔4秒 运行一次
?问号:
用于日和星期的冲突匹配
例:0 15 12 * 1 MON
这里的和MON起了冲突 因为代表每天 而MON代表周一 并不是每天都是周一 会起冲突
因此应改为0 15 12 ? 1 MON
使用问号来进行冲突匹配
L:Last
W:Workday
C:Calendar
在主程序类上添加@EnableScheduling
注解来开启基于注解的定时任务功能:
@SpringBootApplication
@EnableScheduling // 开启基于注解的定时任务
public class SpringbootTaskApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootTaskApplication.class, args);
}
}
然后 给要进行异步任务的方法上添加@Scheduled
注解即可:
表达式共有六位 每位之间用空格进行分隔
格式:second(秒) minute(分) hour(时) day of month(日) month(月) day of week(周几)
例:0 * * * * MON-FRI 代表周一到周五 每分钟启动一次
@Scheduled(cron = "0 * * * * MON-SAT")
public void hello()
{
System.out.println("Hello");
}
部分cron表达式案例:
0 0/5 14,18 * * ?
:每天14点整合18点整 每隔5分钟执行一次
0 15 10 ? * 1-6
:每个月周一到周六的10:15分执行一次
0 0 2 ? * 6L
:每个月的最后一个周六的凌晨2点执行一次
0 0 2 LW * ?
:每个月的最后一个工作日的凌晨2点执行一次
0 0 2-4 ? * 1#1
:每个月的第一个周一的凌晨2点到4点这期间 每个整点执行一次(会执行三次:分别是2点 3点 4点执行)
三、邮件任务
邮件发送的流程是这样的:
例如 一个qq邮箱要发送到163邮箱
发邮件的时候 并不是两个邮箱地址直接交互的
而是发送者(qq邮箱)要先用账号密码登录qq邮箱服务器
之后以此账户为名 发送邮件给接收者(163邮箱)
发送的时候是qq邮箱服务器发送邮件给163邮箱服务器
然后接收者从163邮箱服务器获取邮件
邮件发送需要spring-boot-starter-mail
org.springframework.boot
spring-boot-starter-mail
然后 进行配置:
为安全起见 配置的password并不是真实的密码 而是授权码
(在邮箱的设置页面中获取授权码)
# 配置发送者的邮箱用户名
spring.mail.username=1111111111@qq.com
# 配置授权码 并不是真实的密码
spring.mail.password=fcddfhqwzksxjhjg
# 配置SMTP服务器地址
spring.mail.host=smtp.qq.com
# 开启使用SSL安全连接
spring.mail.properties.mail.smtp.ssl.enable=true
ps:这个使用SSL安全连接貌似qq邮箱不加也能正常收发
但部分邮箱收发时有可能会报错
首先 注入JavaMailSenderImpl:
@Autowired
JavaMailSenderImpl javaMailSender;
发送简单邮件:
// 创建一个简单邮件信息
SimpleMailMessage simpleMailMessage=new SimpleMailMessage();
// 邮件信息设置
// 设置标题
simpleMailMessage.setSubject("【xx网】恭喜!注册成功!");
// 设置内容
simpleMailMessage.setText("您在xx网刚刚注册了一个账户,接下来您可以尽情使用了。");
// 设置发送目的地邮箱地址
simpleMailMessage.setTo("2222222222@qq.com");
// 设置发送者邮箱地址
simpleMailMessage.setFrom("1111111111@qq.com");
// 发送邮件
javaMailSender.send(simpleMailMessage);
发送成功
发送复杂邮件:
复杂邮件可以带有HTML文本和附件
// 创建一个复杂邮件
MimeMessage mimeMessage = javaMailSender.createMimeMessage();
// 使用MimeMessageHelper 其构造方法传入true代表允许上传文件
MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMessage, true);
// 邮件信息设置
// 设置标题
mimeMessageHelper.setSubject("【xx网】恭喜!注册成功!");
// 设置内容 可以带上HTML样式 其构造方法传入true代表开启识别HTML标签
mimeMessageHelper.setText("您在xx网刚刚注册了一个账户,接下来您可以尽情使用了。",true);
// 设置发送目的地邮箱地址
mimeMessageHelper.setTo("2222222222@qq.com");
// 设置发送者邮箱地址
mimeMessageHelper.setFrom("1111111111@qq.com");
// 上传附件 addAttachment(文件名,文件(可以是File或流之类的))
mimeMessageHelper.addAttachment("1.png",new File("F:\\IdeaProjects\\filetest\\img.png"));
mimeMessageHelper.addAttachment("2.jpg",new File("F:\\IdeaProjects\\filetest\\img2.jpg"));
// 发送邮件
javaMailSender.send(mimeMessage);
发送成功