springboot定时器的使用与源码分析
Posted Fire king
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了springboot定时器的使用与源码分析相关的知识,希望对你有一定的参考价值。
springboot定时器的使用与源码分析
小项目相关依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.quartz-scheduler/quartz -->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context-support -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>5.3.13</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus</artifactId>
<version>3.0.5</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.12</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.11</version>
</dependency>
<!-- https://mvnrepository.com/artifact/eu.bitwalker/UserAgentUtils -->
<dependency>
<groupId>eu.bitwalker</groupId>
<artifactId>UserAgentUtils</artifactId>
<version>1.21</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.1.6.Final</version>
</dependency>
1.线程池高端配置:
1.1.yml
task:
pool:
# 核心线程池大小
core-pool-size: 10
# 最大线程数
max-pool-size: 30
# 活跃时间
keep-alive-seconds: 60
# 队列容量
queue-capacity: 50
1.2.线程池配置属性类
/**
* 线程池配置属性类
* @author https://juejin.im/entry/5abb8f6951882555677e9da2
* @date 2019年10月31日14:58:18
*/
@Data
@Component
@ConfigurationProperties(prefix = "task.pool")
public class AsyncTaskProperties
private int corePoolSize;
private int maxPoolSize;
private int keepAliveSeconds;
private int queueCapacity;
1.3. 用于获取自定义线程池
/**
* 用于获取自定义线程池
* @author hupeng
* @date 2019年10月31日18:16:47
*/
public class ThreadPoolExecutorUtil
public static ThreadPoolExecutor getPoll()
AsyncTaskProperties properties = SpringContextHolder.getBean(AsyncTaskProperties.class);
return new ThreadPoolExecutor(
properties.getCorePoolSize(),
properties.getMaxPoolSize(),
properties.getKeepAliveSeconds(),
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(properties.getQueueCapacity()),
new TheadFactoryName()
);
1.4. 自定义线程名称
/**
* 自定义线程名称
* @author hupeng
* @date 2019年10月31日17:49:55
*/
@Component
public class TheadFactoryName implements ThreadFactory
private static final AtomicInteger POOL_NUMBER = new AtomicInteger(1);
private final ThreadGroup group;
private final AtomicInteger threadNumber = new AtomicInteger(1);
private final String namePrefix;
public TheadFactoryName()
this("el-pool");
private TheadFactoryName(String name)
SecurityManager s = System.getSecurityManager();
group = (s != null) ? s.getThreadGroup() :
Thread.currentThread().getThreadGroup();
//此时namePrefix就是 name + 第几个用这个工厂创建线程池的
this.namePrefix = name +
POOL_NUMBER.getAndIncrement();
@Override
public Thread newThread(Runnable r)
//此时线程的名字 就是 namePrefix + -thread- + 这个线程池中第几个执行的线程
Thread t = new Thread(group, r,
namePrefix + "-thread-" + threadNumber.getAndIncrement(),
0);
if (t.isDaemon())
t.setDaemon(false);
if (t.getPriority() != Thread.NORM_PRIORITY)
t.setPriority(Thread.NORM_PRIORITY);
return t;
2.定时器高端定制
2.1.定时任务实体类:
@Data
@TableName("quartz_job")
public class QuartzJob implements Serializable
public static final String JOB_KEY = "JOB_KEY";
/** 定时任务ID */
@TableId
private Long id;
/** Spring Bean名称 */
private String beanName;
/** cron 表达式 */
private String cronExpression;
/** 状态:1暂停、0启用 */
private Boolean isPause;
/** 任务名称 */
private String jobName;
/** 方法名称 */
private String methodName;
/** 参数 */
private String params;
/** 备注 */
private String remark;
/** 创建时间 */
@TableField(fill = FieldFill.INSERT)
private Timestamp createTime;
public void copy(QuartzJob source)
BeanUtil.copyProperties(source, this, CopyOptions.create().setIgnoreNullValue(true));
2.2.为获取环境的类提供获取bean的上下文:
@Slf4j
public class SpringContextHolder implements ApplicationContextAware, DisposableBean
private static ApplicationContext applicationContext = null;
/**
* 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
*/
@SuppressWarnings("unchecked")
public static <T> T getBean(String name)
assertContextInjected();
return (T) applicationContext.getBean(name);
/**
* 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
*/
public static <T> T getBean(Class<T> requiredType)
assertContextInjected();
return applicationContext.getBean(requiredType);
/**
* 检查ApplicationContext不为空.
*/
private static void assertContextInjected()
if (applicationContext == null)
throw new IllegalStateException("applicaitonContext属性未注入, 请在applicationContext" +
".xml中定义SpringContextHolder或在SpringBoot启动类中注册SpringContextHolder.");
/**
* 清除SpringContextHolder中的ApplicationContext为Null.
*/
private static void clearHolder()
log.debug("清除SpringContextHolder中的ApplicationContext:"
+ applicationContext);
applicationContext = null;
@Override
public void destroy()
SpringContextHolder.clearHolder();
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
if (SpringContextHolder.applicationContext != null)
log.warn("SpringContextHolder中的ApplicationContext被覆盖, 原有ApplicationContext为:" + SpringContextHolder.applicationContext);
SpringContextHolder.applicationContext = applicationContext;
2.3.为执行任务的类获取环境:
/**
* 执行定时任务
* @author /
*/
@Slf4j
public class QuartzRunnable implements Callable
private Object target;
private Method method;
private String params;
QuartzRunnable(String beanName, String methodName, String params)
throws NoSuchMethodException, SecurityException
this.target = SpringContextHolder.getBean(beanName);
this.params = params;
if (StringUtils.isNotBlank(params))
this.method = target.getClass().getDeclaredMethod(methodName, String.class);
else
this.method = target.getClass().getDeclaredMethod(methodName);
@Override
public Object call() throws Exception
ReflectionUtils.makeAccessible(method);
if (StringUtils.isNotBlank(params))
method.invoke(target, params);
else
method.invoke(target);
return null;
2.4.真正执行任务的类:
@Async
public class ExecutionJob extends QuartzJobBean
private Logger logger = LoggerFactory.getLogger(this.getClass());
/** 该处仅供参考 */
private final static ThreadPoolExecutor EXECUTOR = ThreadPoolExecutorUtil.getPoll();
@Override
@SuppressWarnings("unchecked")
protected void executeInternal(JobExecutionContext context)
//继承了QuartzJob,也就拥有QuartzJob.JOB_KEY属性,通过context就能获取与QuartzManage中的QuartzJob
QuartzJob quartzJob = (QuartzJob) context.getMergedJobDataMap().get(QuartzJob.JOB_KEY);
// 获取spring bean
TestQuartz quartzJobService = SpringContextHolder.getBean(TestQuartz.class);
long startTime = System.currentTimeMillis();
try
// 执行任务
logger.info("任务准备执行,任务名称:", quartzJob.getJobName());
QuartzRunnable task = new QuartzRunnable(quartzJob.getBeanName(), quartzJob.getMethodName(),
quartzJob.getParams());
Future<?> future = EXECUTOR.submit(task);
future.get();
long times = System.currentTimeMillis() - startTime;
// 任务状态
logger.info("任务执行完毕,任务名称: 总共耗时: 毫秒", quartzJob.getJobName(), times);
catch (Exception e)
logger.error("任务执行失败,任务名称:" + quartzJob.getJobName(), e);
long times = (System.currentTimeMillis() - startTime);
quartzJob.setIsPause(false);
//更新状态
//quartzJobService.updateIsPause(quartzJob);
finally
//quartzLogService.save(log);
2.5.任务管理类:
专门暴露给客户端用的,主要用到addJob(QuartzJob quartzJob)
这个方法
@Slf4j
@Component
public class QuartzManage
private static final String JOB_NAME = "TASK_";
@Resource(name = "scheduler")
private Scheduler scheduler;
public void addJob(QuartzJob quartzJob)
try
// 构建job信息
/*
ExecutionJob.class必须继承或间接继承Job类
* */
JobDetail jobDetail = JobBuilder.newJob(ExecutionJob.class).
withIdentity(JOB_NAME + quartzJob.getId()).build();
//通过触发器名和cron 表达式创建 Trigger
Trigger cronTrigger = newTrigger()
.withIdentity(JOB_NAME + quartzJob.getId())
.startNow()
.withSchedule(CronScheduleBuilder.cronSchedule(quartzJob.getCronExpression()))
.build();
cronTrigger.getJobDataMap().put(QuartzJob.JOB_KEY, quartzJob);
//重置启动时间
((5w字SpringBoot源码分析
UEFI.源码分析.DXE的异步事件服务.第三部分.定时器与时钟中断