栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

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

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

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

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


   org.springframework.boot
   spring-boot-starter-mail

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

 
    
      org.springframework.boot
      spring-boot-starter
      2.5.4
      compile
    
    
      org.springframework
      spring-context-support
      5.3.9
      compile
    
    
      com.sun.mail
      jakarta.mail
      1.6.7
      compile
    
  

照例我们从启动器下通过发现机制查看自动配置类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自动配置原理,了解之后看到相关代码能立刻看懂也还是大有好处。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/331984.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号