com.xxl.job.spring.boot.XxlJobAutoBindingSpringExecutor Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of xxljob-spring-boot-starter Show documentation
Show all versions of xxljob-spring-boot-starter Show documentation
Spring Boot Starter For XXL-Job
The newest version!
/*
* Copyright (c) 2018, hiwepy (https://github.com/hiwepy).
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.xxl.job.spring.boot;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.executor.impl.XxlJobSpringExecutor;
import com.xxl.job.core.glue.GlueFactory;
import com.xxl.job.core.handler.annotation.XxlJob;
import com.xxl.job.spring.boot.annotation.XxlJobCron;
import com.xxl.job.spring.boot.model.XxlJobGroup;
import com.xxl.job.spring.boot.model.XxlJobGroupList;
import com.xxl.job.spring.boot.model.XxlJobInfo;
import com.xxl.job.spring.boot.model.XxlJobInfoList;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Lazy;
import org.springframework.core.MethodIntrospector;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import java.lang.reflect.Method;
import java.util.*;
/**
* Xxl Job Handler 自动注册
* @author : wandl
*/
@Slf4j
public class XxlJobAutoBindingSpringExecutor extends XxlJobSpringExecutor {
private XxlJobTemplate xxlJobTemplate;
private String appName;
private String appTitle;
private List cacheJobs = new ArrayList<>();
private Random RANDOM_ORDER = new Random(10);
public XxlJobAutoBindingSpringExecutor(XxlJobTemplate xxlJobTemplate) {
this.xxlJobTemplate = xxlJobTemplate;
}
@Override
public void setAppname(String appName) {
super.setAppname(appName);
this.appName = appName;
}
public void setAppTitle(String appTitle) {
this.appTitle = appTitle;
}
// start
@Override
public void afterSingletonsInstantiated() {
// init JobHandler Repository
/*initJobHandlerRepository(applicationContext);*/
// init JobHandler Repository (for method)
initJobHandlerMethodRepository(applicationContext);
// refresh GlueFactory
GlueFactory.refreshInstance(1);
// super start
try {
super.start();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private void initJobHandlerMethodRepository(ApplicationContext applicationContext) {
if (applicationContext == null) {
return;
}
// init job handler from method
String[] beanDefinitionNames = applicationContext.getBeanNamesForType(Object.class, false, true);
for (String beanDefinitionName : beanDefinitionNames) {
// get bean
Object bean = null;
Lazy onBean = applicationContext.findAnnotationOnBean(beanDefinitionName, Lazy.class);
if (onBean!=null){
log.debug("xxl-job annotation scan, skip @Lazy Bean:{}", beanDefinitionName);
continue;
}else {
bean = applicationContext.getBean(beanDefinitionName);
}
// filter method
Map annotatedMethods = null; // referred to :org.springframework.context.event.EventListenerMethodProcessor.processBean
try {
annotatedMethods = MethodIntrospector.selectMethods(bean.getClass(),
new MethodIntrospector.MetadataLookup() {
@Override
public XxlJob inspect(Method method) {
return AnnotatedElementUtils.findMergedAnnotation(method, XxlJob.class);
}
});
} catch (Throwable ex) {
log.error("xxl-job method-jobhandler resolve error for bean[" + beanDefinitionName + "].", ex);
}
if (annotatedMethods==null || annotatedMethods.isEmpty()) {
continue;
}
// generate and regist method job handler
for (Map.Entry methodXxlJobEntry : annotatedMethods.entrySet()) {
Method executeMethod = methodXxlJobEntry.getKey();
XxlJob xxlJob = methodXxlJobEntry.getValue();
// regist
registJobHandler(xxlJob, bean, executeMethod);
registJobHandlerCronTaskInfo(xxlJob, bean, executeMethod);
}
registJobHandlerCronTaskToAdmin();
}
}
private void registJobHandlerCronTaskInfo(XxlJob xxlJob, Object bean, Method executeMethod) {
try {
String name = xxlJob.value();
if (!StringUtils.hasText(name)) {
log.error("xxl-job method-jobhandler name invalid, for[" + bean.getClass() + "#" + executeMethod.getName() + "] .");
return;
}
XxlJobCron xxlJobCron = AnnotationUtils.findAnnotation(executeMethod, XxlJobCron.class);
if(Objects.isNull(xxlJobCron)) {
return;
}
XxlJobInfo xxlJobInfo = new XxlJobInfo();
// 任务描述
xxlJobInfo.setJobDesc(xxlJobCron.desc());
// 调度配置,值含义取决于调度类型
xxlJobInfo.setScheduleConf(xxlJobCron.cron());
xxlJobInfo.setJobCron(xxlJobCron.cron());
// 负责人
xxlJobInfo.setAuthor(xxlJobCron.author());
// 报警邮件
xxlJobInfo.setAlarmEmail(xxlJobCron.alarmEmail());
// 调度类型
xxlJobInfo.setScheduleType(xxlJobCron.scheduleType().name());
// 运行模式
xxlJobInfo.setGlueType(xxlJobCron.glueType().name());
// JobHandler
xxlJobInfo.setExecutorHandler(name);
// 任务参数
xxlJobInfo.setExecutorParam(xxlJobCron.param());
// 路由策略
xxlJobInfo.setExecutorRouteStrategy(xxlJobCron.routeStrategy().name());
// 失败重试次数
xxlJobInfo.setExecutorFailRetryCount(xxlJobCron.failRetryCount());
// 调度过期策略
xxlJobInfo.setMisfireStrategy(xxlJobCron.misfireStrategy().name());
// 阻塞处理策略
xxlJobInfo.setExecutorBlockStrategy(xxlJobCron.blockStrategy().name());
// 任务超时时间
xxlJobInfo.setExecutorTimeout(xxlJobCron.timeout());
// 是否自启动
xxlJobInfo.setSelfStarting(xxlJobCron.selfStarting());
cacheJobs.add(xxlJobInfo);
} catch (Exception ex){
log.error(ex.getMessage());
}
}
public void registJobHandlerCronTaskToAdmin() {
try {
// 检查执行器是否存在
if(!StringUtils.hasText(appName)) {
return;
}
// 检查任务组是否存在
ReturnT returnT1 = getXxlJobTemplate().jobInfoGroupList(0, Integer.MAX_VALUE, appName, null);
if (returnT1.getCode() == ReturnT.FAIL_CODE) {
log.error(">>>>>>>>>>> 执行器查询失败!失败原因:{}", returnT1.getMsg());
return;
}
// 执行器不存在则创建
XxlJobGroupList jobGroupList = returnT1.getContent();
Integer jobGroupId = null;
if(Objects.isNull(jobGroupList) || CollectionUtils.isEmpty(jobGroupList.getData())
|| jobGroupList.getData().stream().noneMatch(xxlJobGroup -> xxlJobGroup.getAppName().equals(appName))) {
log.info(">>>>>>>>>>> 执行器'{}'不存在,开始自动添加!", appName);
// 创建任务组对象
XxlJobGroup xxlJobGroup = new XxlJobGroup();
xxlJobGroup.setAppName(appName);
xxlJobGroup.setAddressType(0);
xxlJobGroup.setOrder(RANDOM_ORDER.nextInt(1000));
xxlJobGroup.setTitle(appTitle);
ReturnT returnT2 = getXxlJobTemplate().addJobGroup(xxlJobGroup);
if (returnT2.getCode() == ReturnT.FAIL_CODE) {
log.error( ">>>>>>>>>>> 执行器'{}'添加添加失败!失败原因:{}", appName, returnT2.getMsg());
return;
}
returnT1 = getXxlJobTemplate().jobInfoGroupList(0, Integer.MAX_VALUE, appName, null);
if (returnT1.getCode() == ReturnT.FAIL_CODE) {
log.error(">>>>>>>>>>> 执行器查询失败!失败原因:{}", returnT1.getMsg());
return;
}
jobGroupList = returnT1.getContent();
} else {
jobGroupId = jobGroupList.getData().stream().filter(xxlJobGroup -> xxlJobGroup.getAppName().equals(appName)).findFirst().get().getId();
}
// 定时任务是否存在
ReturnT returnT3 = getXxlJobTemplate().jobInfoList(0, Integer.MAX_VALUE, jobGroupId);
if (returnT3.getCode() == ReturnT.FAIL_CODE) {
log.error(">>>>>>>>>>> 定时任务查询失败!失败原因:{}", returnT3.getMsg());
return;
}
XxlJobInfoList jobInfoList = returnT3.getContent();
// 执行器存在或者创建成功,添加定时任务
for (XxlJobInfo xxlJobInfo : cacheJobs) {
xxlJobInfo.setJobGroup(jobGroupId);
log.info(">>>>>>>>>>> xxl-job cron task register jobhandler, name:{}, cron :{}", xxlJobInfo.getExecutorHandler(), xxlJobInfo.getScheduleConf());
if(Objects.isNull(jobInfoList) || CollectionUtils.isEmpty(jobInfoList.getData())
|| jobInfoList.getData().stream().noneMatch(jobInfo -> jobInfo.getExecutorHandler().equals(xxlJobInfo.getExecutorHandler())
)) {
log.info(">>>>>>>>>>> 不存在 ExecutorHandler = {} 的定时任务,开始自动添加!", xxlJobInfo.getExecutorHandler());
// 自动添加定时任务
ReturnT returnT4 = getXxlJobTemplate().addJob(xxlJobInfo);
if (returnT4.getCode() == ReturnT.FAIL_CODE) {
log.error(">>>>>>>>>>> 自动添加 ExecutorHandler = {} 的定时任务失败!失败原因:{}", xxlJobInfo.getExecutorHandler(), returnT4.getMsg());
} else {
log.info(">>>>>>>>>>> 自动添加 ExecutorHandler = {} 的定时任务成功!", xxlJobInfo.getExecutorHandler());
xxlJobInfo.setId(Integer.valueOf(returnT4.getContent()));
}
} else {
Optional optional = jobInfoList.getData().stream().filter(jobInfo -> jobInfo.getExecutorHandler().equals(xxlJobInfo.getExecutorHandler())).findFirst();
xxlJobInfo.setId(optional.get().getId());
log.info(">>>>>>>>>>> 存在 JobId = {}, ExecutorHandler = {} 的定时任务,开始自动更新!", xxlJobInfo.getId(), xxlJobInfo.getExecutorHandler());
ReturnT returnT4 = getXxlJobTemplate().updateJob(xxlJobInfo);
if (returnT4.getCode() == ReturnT.FAIL_CODE) {
log.error(">>>>>>>>>>> 自动更新 JobId = {}, ExecutorHandler = {} 的定时任务失败!失败原因:{}", xxlJobInfo.getId(), xxlJobInfo.getExecutorHandler(), returnT4.getMsg());
} else {
log.info(">>>>>>>>>>> 自动更新 JobId = {}, ExecutorHandler = {} 的定时任务成功!", xxlJobInfo.getId(), xxlJobInfo.getExecutorHandler());
}
}
// 如果是自启动,则启动任务
if(xxlJobInfo.isSelfStarting() && Objects.nonNull(xxlJobInfo.getId())){
ReturnT returnT4 = getXxlJobTemplate().startJob(xxlJobInfo.getId());
if (returnT4.getCode() == ReturnT.FAIL_CODE) {
log.error(">>>>>>>>>>> 自动启动 ExecutorHandler = {} 的定时任务失败!失败原因:{}", xxlJobInfo.getExecutorHandler(), returnT3.getMsg());
} else {
log.info(">>>>>>>>>>> 自动启动 ExecutorHandler = {} 的定时任务成功!", xxlJobInfo.getExecutorHandler());
}
}
}
} catch (Exception ex){
log.error(ex.getMessage());
}
}
public XxlJobTemplate getXxlJobTemplate() {
return xxlJobTemplate;
}
// ---------------------- applicationContext ----------------------
public ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy