Spring Boot定时任务

标签: 无 分类: 未分类 创建时间:2020-05-07 02:16:31 更新时间:2024-11-15 10:49:43

1.基本用法

定时任务很简单,指定多长时间执行一个任务。
(1) 在main类上添加注解@EnableScheduling

(2) 在@Component组件类中添加@Scheduled注解

1
2
3
4
5
6
7
8
9
10
11
@Component
public class ScheduledTasks {

private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");

@Scheduled(fixedRate = 5000)
public void reportCurrentTime() {
System.out.println("现在时间:" + dateFormat.format(new Date()));
}

}

SpringBoot Quartz 无法使用@Autowired注入

今天给实习生解决一个问题,就是使用使用Quartz进行定时任务时,总是无法使用@Autowired注入service,包空指针错误(吐槽下自己的技术,确实没有练到家啊,实习生来问我问题,我确实连解决的思路都没有,惭愧啊,惭愧)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@DisallowConcurrentExecution
public class LogJob implements Job {

private Logger log = LoggerFactory.getLogger(LogJob.class);
@Autowired
private DDlogInfoService dDlogInfoService;

@Override
public void execute(JobExecutionContext jobExecutionContext) {
try {
for (int i = 0; i < 100; i++) {
log.error("DDlogInfoService:"+dDlogInfoService);
log.error("DDlogInfoService: two",dDlogInfoService);
dDlogInfoService.logTomyServer(userlogs);
}
}catch (Exception e){
e.printStackTrace();
}
}

经过查阅资料,确实有很多的人遇到了这个问题。在使用Spring自带的定时任务注解@Scheduled时,同样在任务执行类中使用了Service,好像并没有出现这个问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
/**
* 任务执行类
*/
@Component
public class ClickhouseImport {
private final static Logger logger= LoggerFactory.getLogger(ClickhouseImport.class);
@Resource
private RealTimeMapper realTimeMapper;

@Autowired
private ClickhouseDbUtil clickhouseDbUtil;

public void insertClickhouse(String startdate,String enddate){
try {
List<RealTime> result=realTimeMapper.selectBetweenDate(startdate,enddate);
}catch (Exception e){
logger.error("getBetween",e);
}
}
}

/*定时任务类*/
@Component
public class ScheduledTasks {
private final static Logger logger = LoggerFactory.getLogger(ScheduledTasks.class);

@Autowired
private ClickhouseImport clickhouseImport;

@Scheduled(fixedDelay = 50*1000)
public void timingImportData() {
try {

// 插入到clickhouse数据库中
clickhouseImport.insertClickhouse("startdate","enddate");

}catch (Exception e){
logger.error("",e);
}

}
}

(3) 我依次实现了QuartzSchedule和AdaptableJobFactory,依然还是不行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Component
public class MyJobFactory extends AdaptableJobFactory{
@Autowired
private AutowireCapableBeanFactory capableBeanFactory;

@Override
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
// 调用父类的方法
Object jobInstance = super.createJobInstance(bundle);
// 进行注入
capableBeanFactory.autowireBean(jobInstance);
return jobInstance;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@Configuration
@EnableScheduling
public class QuartzSchedule {

@Autowired
private MyJobFactory myJobFactory;

@Bean
public SchedulerFactoryBean schedulerFactoryBean() throws IOException {
SchedulerFactoryBean factory = new SchedulerFactoryBean();
System.out.println("dsf");
factory.setOverwriteExistingJobs(true);

// 延时启动
factory.setStartupDelay(20);
// factory.setTriggers(quartzTaskServiceTrigger());



// 自定义Job Factory,用于Spring注入
factory.setJobFactory(myJobFactory);

return factory;
}
}

我又回到了最初的代码,在CommandLineRunner实现类中,直接调用注入DDlogInfoService,是可以的,但是在任务类LogJob中,却出现了空指针的异常。会不会是CommandLineRunner

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@Component
public class MyCommandLineRunner implements CommandLineRunner {
private final Logger log = LogManager.getLogger(MyCommandLineRunner.class);
@Autowired
private DDlogInfoService dDlogInfoService;

@Override
public void run(String... args) {
// 1、创建调度器Scheduler
try{
log.error("s",dDlogInfoService);
SchedulerFactory schedulerFactory = new StdSchedulerFactory();
Scheduler scheduler = schedulerFactory.getScheduler();
// 2、创建JobDetail实例,并与PrintWordsJob类绑定(Job执行内容)
JobDetail build = JobBuilder.newJob(LogJob.class).withIdentity("job1", "group1").build();
Trigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "triggerGroup1")
.withSchedule(CronScheduleBuilder.cronSchedule("* * * * * ? ")).build();
scheduler.scheduleJob(build,trigger);
scheduler.start();

}catch (Exception e){
e.printStackTrace();
}

}

}
参考文章:
1.Spring Boot Quartz 使用介绍
2.SpringBoot集成Quartz实现定时任务
3.myNameIssls/springboot-study
4.springboot整合quartz,报空指针错误,无法取得bean (这篇文章介绍了如何通过扩展AdaptableJobFactor类来实现在接口中注入bean的方法,但是缺少介绍的是如何定义Job任务)
5.Quartz-job的quartz.properties配置文件说明

(4) 经过多方探索和尝试,最终找到了正确的使用方法。

1.pom.xml中引入插件

1
2
3
4
5
6
7
8
9
10
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.2.1</version>
</dependency>
<!--或者是-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>

2.编写任务类

编写任务类,定时执行代码,扩展QuartzJobBean,调用@Autowired注入服务层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@DisallowConcurrentExecution
@Component
public class LogJob extends QuartzJobBean {

private Logger log = LoggerFactory.getLogger(LogJob.class);

@Autowired
private DDlogInfoService dDlogInfoService;


@Override
public void executeInternal(JobExecutionContext jobExecutionContext) {
try {

log.error("",dDlogInfoService);
}catch (Exception e){
e.printStackTrace();
}
}

}

3.编写配置类

编写配置类,注入任务Bean

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@Configuration
@EnableScheduling
public class QuartzSchedule {
/**
* JobDetail 用于指定定时任务具体的类
*/
@Bean
public JobDetail quartzTaskServiceJobDetail() {
return JobBuilder.newJob(LogJob.class).withIdentity("quartzTaskService").storeDurably().build();
}

/**
* Trigger 用于指定定时任务触发的机制
*/
@Bean
public Trigger quartzTaskServiceTrigger() {
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule("* * * * * ?");
return TriggerBuilder.newTrigger().forJob(quartzTaskServiceJobDetail())
.withIdentity("quartzTaskService")
.withSchedule(scheduleBuilder)
.build();
}
}

这样就可以正常的通过@Autowired注入服务层的内容了。

至于为何通过Job接口并且结合AdaptableJobFactory无法实现的问题,还有待进一步探讨

4.动态配置

动态配置定时任务,就是说以前的定时任务都是代码中写死的,如何实现通过代码的方式动态修改定时任务呢?本来要一天执行一次的,现在一个小时执行一次。

小额赞助
本人提供免费与付费咨询服务,感谢您的支持!赞助请发邮件通知,方便公布您的善意!
**光 3.01 元
Sun 3.00 元
bibichuan 3.00 元
微信公众号
广告位
诚心邀请广大金主爸爸洽谈合作
每日一省
isNaN 和 Number.isNaN 函数的区别?

1.函数 isNaN 接收参数后,会尝试将这个参数转换为数值,任何不能被转换为数值的的值都会返回 true,因此非数字值传入也会返回 true ,会影响 NaN 的判断。

2.函数 Number.isNaN 会首先判断传入参数是否为数字,如果是数字再继续判断是否为 NaN ,不会进行数据类型的转换,这种方法对于 NaN 的判断更为准确。

每日二省
为什么0.1+0.2 ! == 0.3,如何让其相等?

一个直接的解决方法就是设置一个误差范围,通常称为“机器精度”。对JavaScript来说,这个值通常为2-52,在ES6中,提供了Number.EPSILON属性,而它的值就是2-52,只要判断0.1+0.2-0.3是否小于Number.EPSILON,如果小于,就可以判断为0.1+0.2 ===0.3。

每日三省
== 操作符的强制类型转换规则?

1.首先会判断两者类型是否**相同,**相同的话就比较两者的大小。

2.类型不相同的话,就会进行类型转换。

3.会先判断是否在对比 null 和 undefined,是的话就会返回 true。

4.判断两者类型是否为 string 和 number,是的话就会将字符串转换为 number。

5.判断其中一方是否为 boolean,是的话就会把 boolean 转为 number 再进行判断。

6.判断其中一方是否为 object 且另一方为 string、number 或者 symbol,是的话就会把 object 转为原始类型再进行判断。

每日英语
Happiness is time precipitation, smile is the lonely sad.
幸福是年华的沉淀,微笑是寂寞的悲伤。