Spring Boot 执行定时任务

2020-06-02 09:51:26 浏览数 (1)

Spring Boot中可以使用注解实现定时任务,十分方便。今天的文章我们首先讲一下个人的项目,然后在文章后面我们将定时任务与线程池结合起来实现每天的个人支出的计算。

最近在学习Spring Security的时候顺便想给自己做一个资产管理的系统,出于学习的目的很多东西都没做好,只做了一个新增支出的功能。使用到的框架有Spring Boot,Spring Security,Mybatis。数据库使用的是sqlserver(Mac安装SqlServer需要Docker实现,大家可以学习一下Docker)。

那我们步入正题。

01

使用支付宝的记账本,不能让我知道我每天支出多少,因为我大多数懒得去看,我就想通过自己记账的动作来让自己逐渐养成理财的习惯。既然是资金管理那么首先我们就要记录支出了(关于登录我就不再多说了前面Spring Security的文章中讲到登录的安全访问,Spring Security项目地址:https://github.com/xynuSuMu/SpringSecurity.git):

在这里我们可以一笔一笔的记录自己每天支出。同时我自己也记录了6号到10号的支出明细,然后现在就有一个问题了,每天有好多笔支出,我想知道每天支出到底多少钱,此时我就想到定时器了。在Spring Boot中使用定时器的方式有好几种方式,我这里选择最快捷的注解方式(如下代码)。

Component我想大家很熟悉,组件的意思。被此注解修饰的类会实例化到Spring容器中,这里如何不写这个注解定时任务不会被触发。EnableScheduling提供了快速的基于多种规则的任务调度功能。Scheduled就是配合EnableScheduling快速开启任务调度功能。所以我们在一个自定义的类中,添加这三个注解就实现定时器的实现。

代码语言:javascript复制
@Component
@EnableScheduling
public class Scheduling {

    @Autowired
    private PayService payService;
    @Scheduled(cron = "0 */1 * * * ?")
    private void countMoney() {
        FundThreadPool.singleton.getFixedInstance().submit(new Runnable() {
            @Override
            public void run() {
                System.out.println(payService.countMoney());
            }
        });
    }
}

FundThreadPool是一个枚举类,负责提供一个单例的线程池类。ExecutorService

Java通过Executors提供四种线程池,分别为:

newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。 newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。 newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。 newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

这里我使用定长的线程池。上面四种线程池实际上还是执行ThreadPoolExecutor的构造器,只不过参数不同。

代码语言:javascript复制
public enum FundThreadPool {
    singleton;
    private ExecutorService executorService;
    private Logger logger = LoggerFactory.getLogger(FundThreadPool.class);

    FundThreadPool() {
        logger.info("调用线程池");
//        定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
        executorService = Executors.newFixedThreadPool(3);

    }

    public ExecutorService getFixedInstance() {
        return executorService;
    }
}

现在我们实现了定时器结合线程池获取前一天的开销,那么这个开销是怎么去计算的呢?我这里通过SQL语句去实现的,这里DATEDIFF函数用于SQL Server中,和MySQL中的函数是有区别的,MySQL 中DATEDIFF函数只有两个日期参数,返回两个日期之间的天数。SQL Server中可以指定类型。getDate()是获取当前的日期,date是数据库你设计的日期字段,=1表明查询昨天的数据。

代码语言:javascript复制
    <select id="countMoney" resultType="java.lang.Integer">
        SELECT sum (money) as money 
        from payInfo 
        where 
        DATEDIFF(DD,date,getDate())=1;
    </select>

0 人点赞