【SpringBoot学习笔记 十二】SpringBoot异步任务、定时任务、邮件任务

简介: 【SpringBoot学习笔记 十二】SpringBoot异步任务、定时任务、邮件任务

之前两篇Blog都是SpringBoot使用层面上的实践,拦截器和异常处理。今天这篇Blog也一样,从使用实践层面上看看SpringBoot给我们封装了什么,能让我们便利的进行异步任务、定时任务、邮件任务的处理。在没有SpringBoot之前,这些功能可能的实现可能需要写很多代码才能实现,同时这篇Blog是SpringBoot实践层面的最后一篇,接下来我们进入集成层面的学习,学习SpringBoot集成Swagger、Dubbo做个小预告,集成内容学习完就开始SpringCloud旅程。

SpringBoot异步任务

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

同步的情况下

首先我们编写一个10秒左右的任务,编写方法,假装正在处理数据,使用线程设置一些延时,模拟同步等待的情况:

AsyncService

package com.example.springboot.service;
import org.springframework.stereotype.Service;
@Service
public class AsyncService {
    public void asyncTask(){
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("业务进行中....");
    }
}

然后我们编写一个用户请求的方法。

AsyncController

package com.example.springboot.controller;
import com.example.springboot.service.AsyncService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@RestController
public class AsyncController {
    @Resource
    AsyncService asyncService;
    @GetMapping("/asyncTask")
    public String asyncTask(){
        asyncService.asyncTask();
        return "success";
    }
}

访问http://localhost:8080/asyncTask进行测试,10秒后出现success,这是同步等待的情况.

10秒后业务执行完了才返回响应

异步的情况下

我们如果想让用户直接得到响应,就在后台使用多线程的方式异步调用AsyncService.asyncTask方法即可,但是每次都需要自己手动去编写多线程的实现的话,太麻烦了。

1 编写AsyncService异步任务类

SpringBoot都帮我们做了,我们只需要在我们的方法上加一个简单的注解即可,给asyncTask方法添加@Async注解

AsyncService

package com.example.springboot.service;
import org.springframework.stereotype.Service;
@Service
public class AsyncService {
    public void asyncTask(){
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("业务进行中....");
    }
}

2 SpringbootApplication 开启异步注解功能

SpringBoot就会自己开一个线程池进行任务异步调用,但是要让这个注解生效,我们还需要在主程序上添加一个注解@EnableAsync ,开启异步注解功能

SpringbootApplication

package com.example.springboot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
@EnableAsync //开启异步注解功能
@SpringBootApplication
public class SpringbootApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringbootApplication.class, args);
    }
}

再次访问http://localhost:8080/asyncTask进行测试,76ms秒后出现success

后台的任务还是10秒执行完。

SpringBoot定时任务

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

1 编写ScheduledService定时任务类

ScheduledService

package com.example.springboot.service;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
@Service
public class ScheduledService {
    //秒   分   时     日   月   周几
    //0 * * * * MON-FRI
    //注意cron表达式的用法;
    @Scheduled(cron = "0/5 * * * * ?")
    public void scheduled(){
        System.out.println("定时任务执行了,现在是:"+ LocalDateTime.now());
    }
}

这里用了cron表达式进行定时任务定制,关于cron表达式,在这篇Blog里我有详细介绍【解决方案 二十】作业调度系统cron表达式详解

2 SpringbootApplication 开启定时任务功能

设置好ScheduledService 后我们需要在主程序上增加@EnableScheduling 开启定时任务功能

SpringbootApplication

package com.example.springboot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
@EnableAsync //开启异步注解功能
@EnableScheduling //开启基于注解的定时任务
@SpringBootApplication
public class SpringbootApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringbootApplication.class, args);
    }
}

启动SpringBoot后我们可以看到异步定时任务每隔5秒执行一次

SpringBoot邮件任务

邮件发送,在我们的日常开发中,也非常的多,Springboot也帮我们做了支持

1 引入pom依赖

邮件发送需要引入spring-boot-start-mail

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

看它引入的依赖,可以看到 jakarta.mail

<dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter</artifactId>
      <version>2.5.4</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context-support</artifactId>
      <version>5.3.9</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>com.sun.mail</groupId>
      <artifactId>jakarta.mail</artifactId>
      <version>1.6.7</version>
      <scope>compile</scope>
    </dependency>
  </dependencies>

照例我们从启动器下通过发现机制查看自动配置类MailSenderAutoConfiguration

MailSenderAutoConfiguration

@Configuration(
    proxyBeanMethods = false
)
@ConditionalOnClass({MimeMessage.class, MimeType.class, MailSender.class})
@ConditionalOnMissingBean({MailSender.class})
@Conditional({MailSenderAutoConfiguration.MailSenderCondition.class})
@EnableConfigurationProperties({MailProperties.class})
@Import({MailSenderJndiConfiguration.class, MailSenderPropertiesConfiguration.class})
public class MailSenderAutoConfiguration {
    public MailSenderAutoConfiguration() {
    }
    static class MailSenderCondition extends AnyNestedCondition {
        MailSenderCondition() {
            super(ConfigurationPhase.PARSE_CONFIGURATION);
        }
        @ConditionalOnProperty(
            prefix = "spring.mail",
            name = {"jndi-name"}
        )
        static class JndiNameProperty {
            JndiNameProperty() {
            }
        }
        @ConditionalOnProperty(
            prefix = "spring.mail",
            name = {"host"}
        )
        static class HostProperty {
            HostProperty() {
            }
        }
    }
}

从导入的MailSenderJndiConfiguration.class向下看:

**MailSenderJndiConfiguration **

@Configuration(
    proxyBeanMethods = false
)
@ConditionalOnClass({Session.class})
@ConditionalOnProperty(
    prefix = "spring.mail",
    name = {"jndi-name"}
)
@ConditionalOnJndi
class MailSenderJndiConfiguration {
    private final MailProperties properties;
    MailSenderJndiConfiguration(MailProperties properties) {
        this.properties = properties;
    }
    @Bean
    JavaMailSenderImpl mailSender(Session session) {
        JavaMailSenderImpl sender = new JavaMailSenderImpl();
        sender.setDefaultEncoding(this.properties.getDefaultEncoding().name());
        sender.setSession(session);
        return sender;
    }
    @Bean
    @ConditionalOnMissingBean
    Session session() {
        String jndiName = this.properties.getJndiName();
        try {
            return (Session)JndiLocatorDelegate.createDefaultResourceRefLocator().lookup(jndiName, Session.class);
        } catch (NamingException var3) {
            throw new IllegalStateException(String.format("Unable to find Session in JNDI location %s", jndiName), var3);
        }
    }
}

发现使用了JavaMailSenderImpl进行邮件发送,同时读取的配置内容来源是:MailProperties

2 定义MailProperties内容配置

我们看下MailProperties 中的配置内容:

所以我们在application.yml中添加如下配置即可:

spring:
  #邮件配置
  mail:
    #邮箱地址
    username: xxxxxtml@qq.com
    #授权码
    password: ofcezjolcpx
    #邮箱服务器
    host: smtp.qq.com
    # qq需要配置ssl
    properties:
       mail:
          smtp:
            ssl:
              enabl: true

3 设置邮箱服务

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

4 SpringTest单元测试调用

在Spring单元测试中填写如下地址

@Resource
    JavaMailSenderImpl mailSender;
    @Test
    public void sendMailTestEasy() {
        //邮件设置1:一个简单的邮件
        SimpleMailMessage message = new SimpleMailMessage();
        message.setSubject("通知-这是来自SpringBoot单元测试的来信,tml请接收");
        message.setText("你有一封SpringBoot单元测试的来信请接收");
        message.setTo("xxxxxtml@qq.com");  //已做打码处理
        message.setFrom("xxxxxtml@qq.com"); //已做打码处理
        //如果需要发送附件
        mailSender.send(message);
    }

然后我们就收到了这封邮件:

总结一下

今天这篇Blog学习了SpringBoot的几个应用场景,异步任务,定时任务以及邮件任务,其实都不复杂,都是使用层面上的小实践,但是也可以看的出SpringBoot的功能之强大,扩展之方便,其实实际使用时我们不一定使用SpringBoot自带的,可能会集成一些三方的系统,但是在了解过程中又过了一遍SpringBoot自动配置原理,了解之后看到相关代码能立刻看懂也还是大有好处。

相关文章
|
3月前
|
前端开发 JavaScript Java
【实操】SpringBoot监听Iphone15邮件提醒,Selenium+Python自动化抢购脚本
本文介绍了一个结合SpringBoot和Python的实用功能,旨在监控iPhone 15的库存状态并通过邮件提醒用户。系统采用SpringBoot监听苹果官网API,解析JSON数据判断是否有货,并展示最近的库存记录。此外,还能自动触发Selenium+Python脚本实现自动化购买。文中详细介绍了技术栈、接口分析、邮件配置及自动化脚本的设置方法。该项目不仅适用于熟悉后端开发的人员,也适合回顾Layui和Jquery等前端技术。
53 0
【实操】SpringBoot监听Iphone15邮件提醒,Selenium+Python自动化抢购脚本
|
3月前
|
Java 开发者 Spring
【SpringBoot 异步魔法】@Async 注解:揭秘 SpringBoot 中异步方法的终极奥秘!
【8月更文挑战第25天】异步编程对于提升软件应用的性能至关重要,尤其是在高并发环境下。Spring Boot 通过 `@Async` 注解简化了异步方法的实现。本文详细介绍了 `@Async` 的基本用法及配置步骤,并提供了示例代码展示如何在 Spring Boot 项目中创建与管理异步任务,包括自定义线程池、使用 `CompletableFuture` 处理结果及异常情况,帮助开发者更好地理解和运用这一关键特性。
183 1
|
2月前
|
存储 安全 Java
SpringBoot异步任务获取HttpServletRequest
通过上述方法,我们可以在Spring Boot应用中的异步任务获取 `HttpServletRequest`,从而实现更为灵活和高效的异步处理逻辑。
264 64
消息中间件 缓存 监控
118 0
|
3月前
|
监控 Java API
Spring Boot中的异步革命:构建高性能的现代Web应用
【8月更文挑战第29天】Spring Boot 是一个简化 Spring 应用开发与部署的框架。异步任务处理通过后台线程执行耗时操作,提升用户体验和系统并发能力。要在 Spring Boot 中启用异步任务,需在配置类上添加 `@EnableAsync` 注解,并定义一个自定义的 `ThreadPoolTaskExecutor` 或使用默认线程池。通过 `@Async` 注解的方法将在异步线程中执行。异步任务适用于发送电子邮件、数据处理、外部 API 调用和定时任务等场景。最佳实践中应注意正确配置线程池、处理返回值和异常、以及监控任务状态,确保系统的稳定性和健壮性。
41 0
|
3月前
|
Java 开发者 Spring
Spring Boot大法好:解耦、隔离、异步,让代码‘活’起来,性能飙升的秘密武器!
【8月更文挑战第29天】解耦、隔离与异步是Spring Boot中的关键设计原则,能大幅提升软件的可维护性、扩展性和性能。本文通过示例代码详细探讨了这些原则的应用:依赖注入和面向接口编程实现解耦;模块化设计与配置文件实现隔离;`@Async`注解和`CompletableFuture`实现异步处理。综合运用这些原则,可以显著提升软件质量和性能,使系统更加健壮、灵活和高效。
37 0
|
4月前
|
Java Spring 容器
Spring boot 自定义ThreadPoolTaskExecutor 线程池并进行异步操作
Spring boot 自定义ThreadPoolTaskExecutor 线程池并进行异步操作
209 3
|
4月前
|
存储 Java Spring
SpringBoot异步任务获取HttpServletRequest
这样的操作对于保持异步操作中的请求上下文十分有用,特别是当你需要在日志记录、权限检查或者其他需要请求信息的场景中。确保上下文的正确传递和管理对于构建可靠的,异步处理能力很强的Spring Boot应用至关重要。
286 3
|
3月前
|
Java 数据安全/隐私保护
SpringBoot 自定义初始化任务 Runner
SpringBoot 自定义初始化任务 Runner
16 0
|
4月前
|
SQL Java 调度
实时计算 Flink版产品使用问题之使用Spring Boot启动Flink处理任务时,使用Spring Boot的@Scheduled注解进行定时任务调度,出现内存占用过高,该怎么办
实时计算Flink版作为一种强大的流处理和批处理统一的计算框架,广泛应用于各种需要实时数据处理和分析的场景。实时计算Flink版通常结合SQL接口、DataStream API、以及与上下游数据源和存储系统的丰富连接器,提供了一套全面的解决方案,以应对各种实时计算需求。其低延迟、高吞吐、容错性强的特点,使其成为众多企业和组织实时数据处理首选的技术平台。以下是实时计算Flink版的一些典型使用合集。