不久前在工作中遇到动态修改定时器的问题,在网上找了一些例子,大部分的写法都差不多,看完过后应用到我的项目中,当时解决了这个问题。但随后我发现这样一个问题:如果再添加一个定时器,在项目启动的时候就会出现SpringBean初始化异常。下面来分析如何解决这个问题:
先来看一下我在百度上看到的此类问题的解决方案, 先修改定时器配置,修改如下:
- 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
- 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
在CustomScheduledJob类中注入schedulerFactory和triggerKey,那么就可以在这个类中修改定时器的时间了。
然而添加多个定时器任务后,随之而来是的项目启动时,SpringBean装载时异常:
org.springframework.beans.factory.BeanCreationException:…Cannot resolve reference to bean ‘scheduledJobFactory’ while setting bean property ‘schedulerFactory’…
不难看出这是在创建定时器时需要scheduledJobFactory,而scheduledJobFactory的triggers的list里有多个触发器,这些触发器都需要实例化,由此出现了嵌套,导致了创建Bean的异常发生,那该如何修正呢?
既然是创建时的嵌套导致的,那我们就要解除嵌套,即在初始化定时器时不要立即传入scheduledJobFactory的Bean,那么把定时器的配置中的ref改成value,如下:
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
那么问题又来了,我们该如何通过value取得spring的Bean呢?
我们可以通过实现接口ApplicationContextAware方式,重写setApplicationContext()的方法,即可取得Spring的Context,然后用getBean()就可以取得Spring容器里的Bean了。
为了把这个问题处理得更漂亮些,可以用一个抽象类去做这些事情,把其中需要的实现的定时任务方法写成抽象方法,每个定时器去继承此抽象类就可以了,抽象类的写法如下:
- 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
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 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
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
自定义的定时器里实现需要处理的计划任务逻辑,写法如下:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
至此,我们的问题得以解决!