SpringBoot-14-异步、定时、邮件任务

本文介绍了如何在SpringBoot中实现异步任务,通过简单的注解实现后台多线程处理,提升用户体验。接着讲解了邮件发送功能,包括配置、依赖和测试过程。最后,讨论了Spring提供的定时任务机制,如TaskExecutor和TaskScheduler接口,以及@Scheduled注解的使用,还给出了cron表达式的常见示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

参考地址:https://mp.weixin.qq.com/s?__biz=Mzg2NTAzMTExNg==&mid=2247483918&idx=1&sn=afadfe906c5f15887fa8e7dad3c8980c&scene=19#wechat_redirect

异步任务

​ 异步处理还是非常常用的,比如我们在网站上发送邮件,后台会去发送邮件,此时前台会造成响应不动,直到邮件发送完毕,响应才会成功,所以我们一般会采用多线程的方式去处理这些任务。

编写方法,假装正在处理数据,使用线程设置一些延时,模拟同步等待的情况

在这里插入图片描述

  1. 创建一个新的 SpringBoot 项目,导入 Web 依赖

  2. 创建 service 包以及 controller 包

  3. 在 service 中创建 AsyncService,并对其模拟异步

    package com.aze.service;
    
    import org.springframework.stereotype.Service;
    
    @Service
    public class AsyncService {
    
        public void hello(){
            try {
                Thread.sleep(3000); // 3s
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("数据正在处理中...");
        }
    
    }
    
  4. 在 controller 包中,创建 AsyncController

    package com.aze.controller;
    
    import com.aze.service.AsyncService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    public class AsyncController {
    
        @Autowired
        AsyncService asyncService;
    
        @RequestMapping("/hello")
        public String hello(){
            asyncService.hello();
            return "OK!";
        }
    
    }
    
  5. 启动项目进行测试,访问http://localhost:8080/hello,发现进入 /hello 需要 3s 才会显示成功,同步等待这就导致了用户体验差了

  6. 如果想让用户直接得到消息,就在后台使用多线程的方式进行处理即可,但是每次都需要自己手动去编写多线程的实现的话,太麻烦了,我们只需要用一个简单的办法,在我们的方法上加一个简单的注解即可

    在这里插入图片描述

    package com.aze.service;
    
    import org.springframework.scheduling.annotation.Async;
    import org.springframework.stereotype.Service;
    
    @Service
    public class AsyncService {
    
        @Async
        public void hello(){
            try {
                Thread.sleep(3000); // 3s
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("数据正在处理中...");
        }
    
    }
    
  7. 添加了以上注解,SpringBoot 就会自动的开启一个线程池进行调用,为了使上面添加的注解生效,还需要在主程序上开启这个注解

    在这里插入图片描述

    package com.aze;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.scheduling.annotation.EnableAsync;
    
    @EnableAsync
    @SpringBootApplication
    public class Springboot10TestApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(Springboot10TestApplication.class, args);
        }
    
    }
    
  8. 启动项目进行测试,访问http://localhost:8080/hello,发现瞬间响应成功,后台代码依然可以完成指定任务

邮件任务

邮件发送

  • 需要引入 spring-boot-start-mail
  • SpringBoot 自动配置 MailSenderAutoConfiguration
  • 定义 MailProperties 内容,配置在 application.yml 中
  • 自动装配 JavaMailSender
  • 测试邮件发送

步骤:

  1. 导入 pom 的相关依赖

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-mail</artifactId>
    </dependency>
    

    spring-boot-starter-mail中可以看到,引入了的依赖jakarta.mail

    <dependency>
      <groupId>com.sun.mail</groupId>
      <artifactId>jakarta.mail</artifactId>
      <version>1.6.5</version>
      <scope>compile</scope>
    </dependency>
    
  2. 查看自动配置类:MailSenderAutoConfiguration

    在这里插入图片描述

    点进MailSenderJndiConfiguration这个类,发现这个类中存在 bean,JavaMailSenderImpl

    在这里插入图片描述

    点进配置文件看看,MailProperties

    在这里插入图片描述

  3. 修改 application.yaml 文件,配置邮箱发送的相关配置

    spring:
      mail:
        # 邮箱账号
        username: xxx@qq.com
        # 邮箱的授权码
        password: xxx
        host: smtp.qq.com
        # QQ 邮箱需要配置 ssl
        properties:
          mail:
            smtp:
              ssl:
                enable: true
    

    注意:获取授权码:在QQ邮箱中的设置->账户->开启pop3和smtp服务

  4. 在单元测试中进行编写邮件,进行测试

    package com.aze;
    
    import org.junit.jupiter.api.Test;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.mail.SimpleMailMessage;
    import org.springframework.mail.javamail.JavaMailSenderImpl;
    import org.springframework.mail.javamail.MimeMessageHelper;
    
    import javax.mail.MessagingException;
    import javax.mail.internet.MimeMessage;
    import java.io.File;
    
    @SpringBootTest
    class Springboot10TestApplicationTests {
    
        @Autowired
        JavaMailSenderImpl mailSender;
    
        @Test
        void contextLoads() {
            // 简单邮件:只包含标题和内容
            SimpleMailMessage simpleMailMessage = new SimpleMailMessage();
            // 邮件标题
            simpleMailMessage.setSubject("这里是标题!");
            // 邮件内容
            simpleMailMessage.setText("这里是邮件的内容!");
            // 发送到哪
            simpleMailMessage.setTo("1031952566@qq.com");
            // 哪里发送的
            simpleMailMessage.setFrom("1031952566@qq.com");
    
            mailSender.send(simpleMailMessage);
        }
    
        @Test
        void test() throws MessagingException {
            // 复杂邮件:包含标题、内容、页面标签内容、附件等
            MimeMessage mimeMessage = mailSender.createMimeMessage();
            MimeMessageHelper helper = new MimeMessageHelper(mimeMessage,true);
            // 标题
            helper.setSubject("这还是一封邮件");
            // 内容
            helper.setText("<h2 style='color:red'>这还是邮件内容</h2>",true);
            // 附件
            helper.addAttachment("图片1.png",new File("C:\\Users\\Hasaki\\Desktop\\1.png"));
            helper.addAttachment("图片2.png",new File("C:\\Users\\Hasaki\\Desktop\\1.png"));
            // 发送到哪
            helper.setTo("1031952566@qq.com");
            // 哪里发送的
            helper.setFrom("1031952566@qq.com");
    
            mailSender.send(mimeMessage);
        }
    }
    
  5. 一个一个进行测试!

定时任务

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

  • TaskExecutor接口
  • TaskScheduler接口

两个注解:

  • @EnableScheduling
  • @Scheduled

cron表达式:

字段允许值允许的特殊符号
0~59, - * /
0~59, - * /
小时0~23, - * /
日期1~31, - * / ? L W C
月份1~12, - * /
星期0~7 或者 SUN~SAT(0和7都是SUN), - * / ? L C #
特殊符号含义
,枚举
-区间
*任意
/步长
?日/星期冲突匹配
L最后
W工作日
C和 calendar 联系后计算过的值
#星期,4#2:第二个星期四

测试

  1. 创建一个ScheduledService,存放一个 hello 方法,每两秒执行

    package com.aze.service;
    
    import org.springframework.scheduling.annotation.Scheduled;
    import org.springframework.stereotype.Service;
    
    @Service
    public class ScheduledService {
    
        // 秒   分   时     日   月   周几
        // 0 * * * * MON-FRI
        // 注意 cron 表达式的用法;
        @Scheduled(cron = "0/2 * * * * ?")
        public void hello(){
            System.out.println("hello!");
        }
    
    }
    
  2. 写完定时任务之后,我们需要在主程序上增加@EnableScheduling开启定时任务功能

    在这里插入图片描述

    package com.aze;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.scheduling.annotation.EnableAsync;
    import org.springframework.scheduling.annotation.EnableScheduling;
    
    @EnableScheduling //开启基于注解的定时任务
    @EnableAsync
    @SpringBootApplication
    public class Springboot10TestApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(Springboot10TestApplication.class, args);
        }
    
    }
    
  3. 进行测试

cron 表达式https://www.bejson.com/othertools/cron/

常用的表达式

  • 0/2 * * * * ? 表示每2秒 执行任务
  • 0 0/2 * * * ? 表示每2分钟 执行任务
  • 0 0 2 1 * ? 表示在每月的1日的凌晨2点调整任务
  • 0 15 10 ? * MON-FRI 表示周一到周五每天上午10:15执行作业
  • 0 15 10 ? 6L 2002-2006 表示2002-2006年的每个月的最后一个星期五上午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 ? * * 每天上午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触发
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值