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

简易定时任务服务模块-SpringCron

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

简易定时任务服务模块-SpringCron

文章目录
  • 前言
  • 代码
    • 一、业务处理
    • 二、线程阻塞问题处理-AOP
    • 三、Feign调用
    • 四、立即执行的控制器接口
  • 总结

前言

提示:这里可以添加本文要记录的大概内容

问题背景:本来想用XXL-JOB进行定时任务处理,但是其目前只有MySQL版本,迁移到 SQL server我又嫌麻烦,所以利用Spring中的@Scheduled进行简单的定时任务的处理。

 

坑点:Spring中的Cron不支持年份,如果通过在线Cron表达式生成的需要把年份列删除,然而实际环境中也很少会用到年份。

代码

思路拆解后主要是四类

  1. 业务处理
  2. 线程问题处理/SpringCron缺点处理
  3. Feign调用
  4. 立即执行的控制器接口
一、业务处理

DemoBusiness示例代码

import org.springblade.aop.TaskThreadHandle;
import org.springframework.scheduling.annotation.Scheduled;


@Component
@EnableScheduling
public class DemoBusiness {

	
	@Scheduled(cron = "0/5 * * * * *")
	@TaskThreadHandle
	public void demoRunSync() throws InterruptedException {
		long startTime = System.currentTimeMillis();
		Thread.sleep(10000);
		System.out.println("=====>>>>>使用cron demoRunSync() {}");
		long lastTime = System.currentTimeMillis();
		System.out.println("demoRunSync()执行时长 = " + (lastTime - startTime) / 1000 + " 秒");
	}
}

这里有个缺点,如果当有一个线程太慢了或者阻塞了,会影响到其它进程的执行,为了解决这个问题点,我做了一个AOP切面+异步线程池,上面已经有了注释说明。

二、线程阻塞问题处理-AOP

接口

public @interface TaskThreadHandle {
}

实现

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springblade.common.tool.ThreadPoolUtils;
import org.springframework.stereotype.Component;
import java.util.concurrent.CompletableFuture;


@Component
@Aspect
public class TaskThreadHandleImpl {

	
	@Around("@annotation(org.springblade.aop.TaskThreadHandle)")
	public Object asyncThreadExecute(ProceedingJoinPoint point) throws Throwable {
		CompletableFuture.runAsync(() -> {
			try {
				point.proceed();
				// 这里应该套一层超时 以后再说
			} catch (Throwable e) {
				throw new RuntimeException(e);
			}
		}, ThreadPoolUtils.getThreadPool());
		// void 也不要返回值了
		return null;
	}
}

这个线程池的工具类

import java.util.concurrent.*;


public class ThreadPoolUtils {

	private static ThreadPoolExecutor pool = null;

	
	public static void execute(Runnable runnable) {
		getThreadPool().execute(runnable);
	}

	
	public static  Future submit(Callable callable) {
		return getThreadPool().submit(callable);
	}

	
	public static synchronized ThreadPoolExecutor getThreadPool() {
		if (pool == null) {
			// 获取处理器数量
			int cpuNum = Runtime.getRuntime().availableProcessors();
			// 根据cpu数量,计算出合理的线程并发数
			// 最佳线程数目 = ((线程等待时间+线程CPU时间)/线程CPU时间 )* CPU数目
			int maximumPoolSize = cpuNum * 2 + 1;
			// 七个参数
			// 1. 核心线程数
			// 2. 最大线程数
			// 3. 空闲线程最大存活时间
			// 4. 时间单位
			// 5. 阻塞队列
			// 6. 创建线程工厂
			// 7. 拒绝策略
			pool = new ThreadPoolExecutor(maximumPoolSize - 1,
				maximumPoolSize,
				5,
				TimeUnit.SECONDS,
				new ArrayBlockingQueue<>(50),
				Executors.defaultThreadFactory(),
				new ThreadPoolExecutor.AbortPolicy());
		}
		return pool;
	}
}
三、Feign调用

在微服务场景下,做定时任务的最终目标肯定是会调用到其它的微服务,所以我这里是这么写的。

import org.springblade.core.tool.utils.SpringUtil;


public class UnifyClient {

	
	private static IOrderClient orderClient;

	public static IOrderClient getOrderClient() {
		if (orderClient == null) {
			orderClient = SpringUtil.getBean(IOrderClient.class);
		}
		return orderClient;
	}
}
四、立即执行的控制器接口

这里没写完,但是以后再补充吧

import org.springframework.web.bind.annotation.RestController;


@RestController
public class TestController {
}
总结

提示:这里对文章进行总结:
例如:以上就是今天要讲的内容。

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

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

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