前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spring任务调度与异步处理

Spring任务调度与异步处理

作者头像
用户10175992
发布2022-11-15 13:32:35
5190
发布2022-11-15 13:32:35
举报
文章被收录于专栏:辰远辰远

1 Spring任务调度

        在实际应用中,有些业务并不是有用户操作执行的,而是根据时间需要去调度的。例如:一个电商系统,可能需要在每天晚上(系统闲时)定时检查商品库存,并把库存量告警的商品汇总成EMAIL发送给系统管理员。这种需要定时执行的事情称为“任务调度”。

Quartz是Java开源世界中最著名的任务调度框架,Spring作为容器框架可以很方便的与Quartz集成;在Spring 3.x之后,Spring甚至内置了轻量级的任务调度功能。如果要实现的任务调度不复杂仅仅Spring就足够了,如果要更复杂的控制,则需要Quartz。

下面简单介绍Spring任务调度的使用。

1.1 使用@Scheduled注解定时调用任务

(1)导入依赖

        实际上@Scheduled就位于spring-context依赖中,因此无需导入额外的依赖。

                 <!-- Spring DI容器 -->

                 <dependency>

                         <groupId>org.springframework</groupId>

                         <artifactId>spring-context</artifactId>

                         <version>4.2.5.RELEASE </version>

                 </dependency>

(2)在spring配置文件中添加task命名空间声明,并开启注解驱动任务调度

        Spring 3.x的任务调度配置,需要导入task命名空间

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

        xmlns:context="http://www.springframework.org/schema/context"

         xmlns:task="http://www.springframework.org/schema/task"

        xsi:schemaLocation="http://www.springframework.org/schema/beans

           http://www.springframework.org/schema/beans/spring-beans.xsd

           http://www.springframework.org/schema/context

           http://www.springframework.org/schema/context/spring-context.xsd

           http://www.springframework.org/schema/task 

           http://www.springframework.org/schema/task/spring-task.xsd">

        ……

        <!-- 注解驱动任务调度 -->

        <task:annotation-driven/>

</beans>

(3)创建任务服务,并标注任务的调度规则

        一般情况下,使用@Scheduled去标记任务调度方法。

        任务调度方法应该是一个“public”修饰的返回“void ”的“无参”方法。

        @Scheduled的“fixedDelay”是任务调用的周期,以毫秒为单位。

        @Scheduled的“initialDelay”是Spring启动后任务开始的延时时间。

@Service

public class ProductJobs {

        @Autowired

        private ProductBiz productBiz;



        @Scheduled(fixedDelay=5000, initialDelay=3000)

        public void checkWarningProducts() throws IOException {

                 //创建以当前“日期时间”为签名的文件

                 Calendar cal = Calendar.getInstance();

                 String path = String.format("d:/Product-Stock.csv",

                                 cal.get(Calendar.YEAR),cal.get(Calendar.MONTH),cal.get(Calendar.DATE),            cal.get(Calendar.HOUR_OF_DAY),cal.get(Calendar.MINUTE),cal.get(Calendar.SECOND));

                 System.out.println("---输出文件:" + path+" ---");

                 BufferedWriter bw = new BufferedWriter(

new OutputStreamWriter( new FileOutputStream(path), "gbk"));

                 //调用并输出数据

                 for(Product p : productBiz.getWarningProducts()) {

                         String line = String.format("%s,%s,%f,%d", p.getCode(), p.getName(), p.getUnitPrice(), p.getQuantity());

                         bw.write(line);

                         bw.newLine();

                 }              

                 bw.flush();

                 bw.close();

        }

}

1.2 使用Cron表达式定义精确的时刻:

        “fixedDelay”只能按时间周期来运行,如果希望在特定时刻(时钟时间)去执行,如晚上0点整,则需要使用Cron表达式。

1.2.1 Cron表达式

(1)Cron表达式由6~7个由空格分隔的时间元素组成,第7个元素可选。Cron表达式的每个字段,都可以显式地规定一个值(如49)、一个范围(如1-6)、一个列表(如1,3,5)或者一个通配符(如*)。

位置

字段含义

范围

允许的特殊字符

1

0~59

*   /

2

分钟

0~59

*   /

3

小时

0~23

*   /

4

月份中的哪一天

1~31

*   /  ? L

5

月份

1~12 或 JAN~DEC

*   /

6

星期几

1~7 或 SUN~SAT

*   /  ? L  #

7

年份

1970~2099

*   /

(2)Cron表达式有几个特殊的字符,说明如下

“ - ”:中划线,表示一个范围

“ , ”:使用逗号间隔的数据,表示一个列表

“ * ”:表示每一个值,它可以用于所有字段。例如:在小时字段表示每小时

“ ? ”:该字符仅用于“月份中的哪一天”字段和“星期几”字段,表示不指定值

“ / ”:通常表示为x/y,x为起始值,y表示值的增量。

“ L ”:表示最后一天,仅在日期和星期字段中使用

“ # ”:只能用于“星期几”字段,表示这个月的第几个周几。例如:“6#3”指这个月第三个周五

(3)一些示例

Cron表达式

含义

0 0 8-12 ? * MON-FRI

每个工作日的8点到12点

0 15 4 * * ?

每天凌晨4点15分

30 0 0 1 1 ? 2014

2014年1月1日凌晨过30秒

0 0 14 1,10,20 * ? *

每月的1号、10号、20号的下午2点

0  0 17 L * ?

每月最后一天17:00运行

0 0 10 ? * 6L

每月最后一个星期五10:00运行

0 0/5 15,17 * * ?

每天15点到16点每5分钟运行一次, 此外,每天17点到18点每5分钟运行一次

0 30 10 ? * 6#3 2013

2013年每月的第三个星期五上午10:30触发

1.2.2 在@Scheduled中使用cron表达式

@Scheduled注解中的cron属性用于设置cron表达式。

@Service

public class ProductJobs {

        ……

        @Scheduled(cron="0 15 11 * * ?")

        public void checkWarningProducts() throws IOException {

                 ……

        }

}

2 Spring异步调用

        Java中的方法通常都是同步调用的,同步意味着可能发生阻塞。如果被调用方法需要访问网络,则难以保证调用的时间,例如发送Email、SMS短信或者Web服务器。这时,我们应该使用异步(多线程)的方式去调用。在传统Java编程中,异步往往要通过多线程来实现,复杂较高。

Spring提供了@Async注解,可以傻瓜式的实现功能的异步调用。

        假设发送一封邮件可能需要一定的时间。

@Service

public class EmailSender {

        public void sendEmail(String to, String content) {

                 System.out.println("---邮件发送开始---");

                 try {

                         Thread.sleep(3000);                //虚拟邮件发送时所耗费的时间

                 } catch (InterruptedException e) {

                         e.printStackTrace();

                 }

                 System.out.println("---邮件发送成功---");

        }

}

        执行该功能时,主程序会一致处在等待之中。

 public static void main(String[] args) {

                 ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-beans.xml");

                 EmailSender emailSender = ctx.getBean(EmailSender.class);

                 emailSender.sendEmail("zhang3@126.com", "测试邮件");

                 System.out.println("继续其他任务...");

        }

        我们可以使用@Async注解,修饰方法,则该方法在调用时会通过另一个线程执行,主程序无需等待。

@Service

public class EmailSender {

        @Async

        public void sendEmail(String to, String content) {

                ……

        }

}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2021-12-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档