Auto-Switch-between-Schedule-And-XXL-Job
背景
在使用XXL—JOB的实现定时任务过程中,有时候可能由于部署环境的要求,就只能用Spring自带的实现方式。
所以为了通用性和灵活性,突发奇想地看看能不能实现在不修改原本Spring定时任务代码的前提下,通过配置灵活控制定时任务具体的实现,同时任务的日志的管理也要同步进行切换。
分析并列出需要解决的问题思路
根据需求背景可以初步分析实现的大致方向和实现流程。实现的思路其实不复杂,重点在于如何具体去实现落地。
具体实现
判断是否启用XXl-JOB的实现方式
和大多数第三方starter包一样 ,我们可以利用SpringBoot的自动装配,读取配置中的某个属性值,作为是否装配我们写的类。特别注意的是SpringBoot不同版本的配置方式有所不同。自动装配类如下:
/**
* 自动装配类
*
* @author Teoan
* @since 2023/04/18 10:18
*/
@Configuration
@ConditionalOnProperty(name = "xxl.job.enable",havingValue = "true")
@ComponentScan("com.teoan.job.auto.core")
public class XxlJobAutoConfiguration {
}
这里我们根据xxl.job.enable 的值,决定是否启用XXl-JOB的实现方式,如果xxl.job.enable 为false,则就什么都不装配不修改实现方式,默认就是Spring自带的实现方式。
扫描并读取注解值
熟悉SpringBoot的的朋友都应该知道,SpringBoot启动的时候,会去扫描目标注解,然后去做对应的初始化操作,比如@Service,@Component就是使被扫描到并将对应的类注入到Spring容器中。所以我们可以按照相同的思路,可以在应用启动就绪之后,扫描@Scheduled注解,对其进行对应的操作。
Spring中的@EventListener注解
Spring中使用@EventListener标记某个方法为应用监听事件的处理逻辑,还能配合异步注解@Async实现异步触发,@EventListener通过传值的方式设置需要被监听的事件类型,比如应用启动时、应用就绪时、启动失败时等,具体有哪些监听的事件,可以参考Spring源码包org.springframework.boot.context.event。现在,我们可以利用Spring提供的监听注解,在应用启动就绪后,扫描对应注解,去实现我们的代码逻辑,同时为了不影响程序的正常启动速度,使用异步执行的方式。伪代码如下:
@Component
@Slf4j
public class JobAutoRegister {
@EventListener(ApplicationReadyEvent.class)
@Async
public void onApplicationEvent(ApplicationReadyEvent event) {
// 执行扫描注解,自动注册xxl-job任务逻辑
}
}
扫描并获取被@Scheduled标记的方法和对象
我们知道,使用@Scheduled注解对应的对象,必须是被Spring所托管的类,定时任务才会生效,所以我们可以扫描被@Component标记的类,再定位@Scheduled注解,获取对应的值、对象、方法等信息。伪代码如下:
private void addJobInfo() {
List<Object> beanList = applicationContext.getBeansWithAnnotation(Component.class).values().stream().toList();
beanList.forEach(bean -> {
Map<Method, Scheduled> annotatedMethods = MethodIntrospector.selectMethods(bean.getClass(),
(MethodIntrospector.MetadataLookup<Scheduled>) method -> AnnotatedElementUtils.findMergedAnnotation(method, Scheduled.class));
annotatedMethods.forEach((k, v) -> {
// 停止Spring自带的定时任务
// 自动注册到xxl-job任务
// 注册xxl-job的任务
});
});
}