当前位置: 首页 > wzjs >正文

大连建站方案保定模板建站定制网站

大连建站方案,保定模板建站定制网站,网站开发岗位实际情况,网站设计基础语言不包括这些内容一、背景 项目存在这样一个场景。程序启动过程中,在Spring的Bean组件注册完毕后,会初始化一些基础数据到数据库中,而项目中有部分定时任务需要依赖这些基础数据才能正常运行。如果直接使用Scheduled注解标注定时任务方法,会导致定…

一、背景

项目存在这样一个场景。程序启动过程中,在Spring的Bean组件注册完毕后,会初始化一些基础数据到数据库中,而项目中有部分定时任务需要依赖这些基础数据才能正常运行。如果直接使用@Scheduled注解标注定时任务方法,会导致定时任务提前执行且执行失败。
基于以上背景,需要将定时任务的注册执行放在数据初始化以后,那么这部分定时任务就需要手动注册且与基础数据初始化操作保持同步执行,保证定时任务的执行一定晚于数据初始化。

二、方案

自定义配置一个定时任务注册器和定时任务执行器,用于处理我们的需求场景。

三、编码实现

通过阅读Spring实现的定时任务源码(篇幅有限,不展开),得知其底层使用的执行器org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler,使用方法org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler#schedule(java.lang.Runnable, org.springframework.scheduling.Trigger)来配置启动定时任务。
因此,我们也使用这个类来启动需要控制执行时机的定时任务,实现代码如下:

package com.jacks.task;import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.scheduling.support.CronTrigger;/*** 配置自定义定时任务执行器** @author Jacks丶* @since 2025-03-16*/
@Configuration
@Slf4j
public class ScheduledConfig implements SchedulingConfigurer {private TaskScheduler scheduler;/*** 配置定时任务注册器,注册器中自定义执行器用于手动执行定时任务** @param taskRegistrar the registrar to be configured*/@Overridepublic void configureTasks(ScheduledTaskRegistrar taskRegistrar) {scheduler = buildScheduler();taskRegistrar.setScheduler(scheduler);}/*** 自定义定时任务执行器,用于执行定时任务** @return 定时任务执行器对象*/@Beanpublic TaskScheduler buildScheduler() {ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();scheduler.setThreadNamePrefix("thread-task-t-");scheduler.setPoolSize(2);return scheduler;}/*** 初始化定时任务,提供给其他Bean对象手动注册定时任务*/public void initScheduledTask() {scheduler.schedule(() -> System.out.println("定时任务执行了..."), new CronTrigger("*/2 * * * * *"));}
}

此时我们的初始化数据的逻辑如下:

package com.jacks.task;import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringApplicationRunListener;
import org.springframework.context.ConfigurableApplicationContext;import java.time.Duration;/*** SpringBoot启动阶段执行** @author Jacks丶* @since 2025-03-16*/
@Slf4j
public class SpringTask implements SpringApplicationRunListener {public SpringTask(SpringApplication application, String[] args) {log.info("hello init SpringTask.");}/*** Springboot应用已就绪,可在此初始化基础数据** @param context   上下文对象,包含Bean对象,可用于获取定时任务配置Bean,然后调用init方法* @param timeTaken 应用准备所花费时间,可用于了解性能*/@Overridepublic void ready(ConfigurableApplicationContext context, Duration timeTaken) {log.info("开始初始化 ....");try {// 模拟数据初始化耗时Thread.sleep(2000);} catch (InterruptedException e) {throw new RuntimeException(e);}log.info("结束初始化 ...");// 获取定时任务配置类bean对象执行初始化方法启动定时任务context.getBean(ScheduledConfig.class).initScheduledTask();}
}

启动类如下:

package com.jacks;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;/*** 启动入口类** @author Jacks丶* @since 2025-03-16*/
@EnableScheduling
@SpringBootApplication
public class DemoApplication {public static void main(String[] args) {SpringApplication.run(DemoApplication.class, args);}
}

此时可见控制台输出:

2025-03-16 18:43:10.489  INFO 17176 --- [           main] com.jacks.DemoApplication                : Started DemoApplication in 0.88 seconds (JVM running for 1.185)
2025-03-16 18:43:10.490  INFO 17176 --- [           main] com.jacks.task.SpringTask                : 开始初始化 ....
2025-03-16 18:43:12.503  INFO 17176 --- [           main] com.jacks.task.SpringTask                : 结束初始化 ...
2025-03-16 18:43:14.006  INFO 17176 --- [thread-task-t-1] com.jacks.task.ScheduledConfig           : 定时任务执行了...
2025-03-16 18:43:16.001  INFO 17176 --- [thread-task-t-1] com.jacks.task.ScheduledConfig           : 定时任务执行了...
2025-03-16 18:43:18.014  INFO 17176 --- [thread-task-t-1] com.jacks.task.ScheduledConfig           : 定时任务执行了...

四、代码优化

如何优雅的将以上逻辑写入到项目中呢?那就需要引入依赖倒置、单一职责等思想。以上代码中,定时任务是直接定义在initScheduledTask方法中的,当我们需要添加定时任务时,那么就会侵入式的修改com.jacks.task.ScheduledConfig#initScheduledTask
基于单一职责思想,定时任务配置类就只负责初始化注册器、执行器和启动定时任务就好,定时任务的定义逻辑就需要提取出去。
基于依赖倒置的思想,我们需要将注册时依赖的具体实现类优化成接口,所以需要抽取接口,让注册依赖接口,而不是具体实现,我们在新增定时任务时,只需要继承接口编写定时任务逻辑即可,无需侵入式的修改原逻辑。

1、定义接口获取定时任务

package com.jacks.service;import org.springframework.scheduling.config.CronTask;import java.util.List;/*** 定时任务接口,用于提供可执行的定时任务对象** @author Jacks丶* @since 2025-03-16*/
public interface IScheduled {/*** 提供定时任务执行对象** @return 定时任务执行对象列表*/List<CronTask> getScheduledTasks();
}

2、在实现类定义定时任务逻辑

package com.jacks.service;import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.config.CronTask;
import org.springframework.stereotype.Service;import java.util.ArrayList;
import java.util.List;/*** 定时任务方法** @author Jacks丶* @since 2025-03-16*/
@Slf4j
@Service
public class MyService implements IScheduled {/*** 定时任务逻辑*/public void task() {log.info("task1 exec..");}/*** 提供定时任务执行对象,用于初始化注册** @return 定时任务列表*/@Overridepublic List<CronTask> getScheduledTasks() {List<CronTask> cronTasks = new ArrayList<>();cronTasks.add(new CronTask(this::task, "*/2 * * * * *"));return cronTasks;}
}

3、单一职责,定时任务抽取为方法入参

package com.jacks.task;import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.config.CronTask;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;import java.util.List;/*** 配置自定义定时任务执行器** @author Jacks丶* @since 2025-03-16*/
@Configuration
@Slf4j
public class ScheduledConfig implements SchedulingConfigurer {private TaskScheduler scheduler;/*** 配置定时任务注册器,注册器中自定义执行器用于手动执行定时任务** @param taskRegistrar the registrar to be configured*/@Overridepublic void configureTasks(ScheduledTaskRegistrar taskRegistrar) {scheduler = buildScheduler();taskRegistrar.setScheduler(scheduler);}/*** 自定义定时任务执行器,用于执行定时任务** @return 定时任务执行器对象*/@Beanpublic TaskScheduler buildScheduler() {ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();scheduler.setThreadNamePrefix("thread-task-t-");scheduler.setPoolSize(2);return scheduler;}/*** 初始化定时任务,提供给其他Bean对象手动注册定时任务** @param cronTasks 待执行的定时任务列表*/public void initScheduledTask(List<CronTask> cronTasks) {cronTasks.forEach(task -> scheduler.schedule(task.getRunnable(), task.getTrigger()));}
}

4、依赖倒置,注册时依赖接口,而不是具体实现

注册定时任务时获取所有com.jacks.service.IScheduled的实现类,并调用getScheduledTasks方法获取定时任务。

package com.jacks.task;import com.jacks.service.IScheduled;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringApplicationRunListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.scheduling.config.CronTask;import java.time.Duration;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;/*** SpringBoot启动阶段执行** @author Jacks丶* @since 2025-03-16*/
@Slf4j
public class SpringTask implements SpringApplicationRunListener {public SpringTask(SpringApplication application, String[] args) {log.info("hello init SpringTask.");}/*** Springboot应用已就绪,可在此初始化基础数据** @param context   上下文对象,包含Bean对象,可用于获取定时任务配置Bean,然后调用init方法* @param timeTaken 应用准备所花费时间,可用于了解性能*/@Overridepublic void ready(ConfigurableApplicationContext context, Duration timeTaken) {log.info("开始初始化 ....");try {// 模拟数据初始化耗时Thread.sleep(2000);} catch (InterruptedException e) {throw new RuntimeException(e);}log.info("结束初始化 ...");// 获取定时任务配置类bean对象执行初始化方法启动定时任务Collection<IScheduled> scheduledServiceList = context.getBeansOfType(IScheduled.class).values();List<CronTask> cronTasks = scheduledServiceList.stream().flatMap(service -> service.getScheduledTasks().stream()).collect(Collectors.toList());context.getBean(ScheduledConfig.class).initScheduledTask(cronTasks);}
}

五、结语

以上就是手动控制注册定时任务时机的一种实现方案,并且这种方案不会影响@Scheduled注解注册的定时任务。
希望本篇博客对你有所帮助。

http://www.dtcms.com/wzjs/839993.html

相关文章:

  • 网站建设报价新鸿儒上海响应式网站
  • 大连做网站优化公司免费管理软件开发平台
  • 系统集成销售和网站建设销售昆明网站搜索优化
  • fifa17做任务网站知名品牌vi设计
  • 凡科外贸网站建设wordpress安装主题打不开
  • 网站被黑应该怎么做wordpress 主题授权
  • 网站怎么添加统计代码成都网站建设公司多少钱
  • 自己做网站能赚钱吗wordpress主题资源分享
  • 重庆网站建设推广公司公司网站建app
  • php做网站浏览量做网站能收多少广告费
  • 邯郸网站建设邯郸网站制作泰安人才网网上办事
  • 做网站需要有公司吗下载app登录
  • 视频变成网站怎么做seo优化前景
  • 做的网站图片模糊网站建设投标文档
  • 求人做网站php后台网站开发
  • 如何判断网站是不是自适应影响网站速度的因素
  • 昆明优化网站排名女性开源网站
  • 商城网站商家入驻功能企业seo可以达到怎样的效果
  • 信誉好的高密网站建设wordpress更新方法
  • 网站建设要些什么做旅行的网站
  • 请将已备案网站接入访问百度账号登录官网
  • 萍乡网站建设萍乡网站备案与不备案的区别
  • 网站空间500m是什么意思王烨简历
  • phpstudy搭建网站教程wordpress顶部颜色改哪
  • 国内做的好网站有哪些seo怎么学
  • 个人房屋做民宿在哪个网站设计说明万能模板500字
  • 旅游网站首页制作没有内容的网站应该怎么做
  • 绵阳市网站建设在线视频
  • 汕头市企业网站建设教程贸易网站有哪些
  • 移动 网站模板旅游网站排名排行榜