Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
Y
yudao-cloud
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
hblj
yudao-cloud
Commits
3774afe5
提交
3774afe5
authored
6月 25, 2022
作者:
YunaiV
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
完成 xxl-job 的接入
上级
4381d938
隐藏空白字符变更
内嵌
并排
正在显示
26 个修改的文件
包含
205 行增加
和
636 行删除
+205
-636
pom.xml
yudao-dependencies/pom.xml
+6
-0
YudaoTenantAutoConfiguration.java
...framework/tenant/config/YudaoTenantAutoConfiguration.java
+16
-12
TenantJobAspect.java
...oder/yudao/framework/tenant/core/job/TenantJobAspect.java
+76
-0
TenantJobHandlerDecorator.java
.../framework/tenant/core/job/TenantJobHandlerDecorator.java
+0
-58
pom.xml
yudao-framework/yudao-spring-boot-starter-job/pom.xml
+15
-6
XxlJobProperties.java
...coder/yudao/framework/quartz/config/XxlJobProperties.java
+20
-93
YudaoQuartzAutoConfiguration.java
...framework/quartz/config/YudaoQuartzAutoConfiguration.java
+0
-21
YudaoXxlJobAutoConfiguration.java
...framework/quartz/config/YudaoXxlJobAutoConfiguration.java
+13
-23
JobDataKeyEnum.java
...der/yudao/framework/quartz/core/enums/JobDataKeyEnum.java
+0
-14
JobHandler.java
...coder/yudao/framework/quartz/core/handler/JobHandler.java
+0
-19
JobHandlerInvoker.java
...udao/framework/quartz/core/handler/JobHandlerInvoker.java
+0
-113
SchedulerManager.java
...dao/framework/quartz/core/scheduler/SchedulerManager.java
+0
-130
JobLogFrameworkService.java
...framework/quartz/core/service/JobLogFrameworkService.java
+0
-44
CronUtils.java
...n/iocoder/yudao/framework/quartz/core/util/CronUtils.java
+0
-54
package-info.java
.../java/cn/iocoder/yudao/framework/quartz/package-info.java
+1
-3
spring.factories
...-starter-job/src/main/resources/META-INF/spring.factories
+1
-1
pom.xml
yudao-module-infra/yudao-module-infra-biz/pom.xml
+5
-5
application-dev.yaml
...-module-infra-biz/src/main/resources/application-dev.yaml
+4
-2
application-local.yaml
...odule-infra-biz/src/main/resources/application-local.yaml
+4
-2
application.yaml
...udao-module-infra-biz/src/main/resources/application.yaml
+9
-0
DemoJob.java
...java/cn/iocoder/yudao/module/system/job/demo/DemoJob.java
+16
-0
application-dev.yaml
...module-system-biz/src/main/resources/application-dev.yaml
+4
-0
application-local.yaml
...dule-system-biz/src/main/resources/application-local.yaml
+5
-0
application.yaml
...dao-module-system-biz/src/main/resources/application.yaml
+10
-0
pom.xml
归档/common/mall-spring-boot-starter-xxl-job/pom.xml
+0
-34
spring.factories
...rter-xxl-job/src/main/resources/META-INF/spring.factories
+0
-2
没有找到文件。
yudao-dependencies/pom.xml
浏览文件 @
3774afe5
...
...
@@ -34,6 +34,7 @@
<!-- Config 配置中心相关 -->
<apollo.version>
1.9.2
</apollo.version>
<!-- Job 定时任务相关 -->
<xxl-job.version>
2.3.1
</xxl-job.version>
<!-- 服务保障相关 -->
<lock4j.version>
2.2.0
</lock4j.version>
<resilience4j.version>
1.7.1
</resilience4j.version>
...
...
@@ -251,6 +252,11 @@
<!-- Config 配置中心相关 -->
<!-- Job 定时任务相关 -->
<dependency>
<groupId>
com.xuxueli
</groupId>
<artifactId>
xxl-job-core
</artifactId>
<version>
${xxl-job.version}
</version>
</dependency>
<dependency>
<groupId>
cn.iocoder.cloud
</groupId>
<artifactId>
yudao-spring-boot-starter-job
</artifactId>
...
...
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/config/YudaoTenantAutoConfiguration.java
浏览文件 @
3774afe5
package
cn
.
iocoder
.
yudao
.
framework
.
tenant
.
config
;
import
cn.hutool.core.annotation.AnnotationUtil
;
import
cn.iocoder.yudao.framework.common.enums.WebFilterOrderEnum
;
import
cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils
;
import
cn.iocoder.yudao.framework.quartz.core.handler.JobHandler
;
import
cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnoreAspect
;
import
cn.iocoder.yudao.framework.tenant.core.db.TenantDatabaseInterceptor
;
import
cn.iocoder.yudao.framework.tenant.core.job.TenantJob
;
import
cn.iocoder.yudao.framework.tenant.core.job.TenantJobHandlerDecorator
;
import
cn.iocoder.yudao.framework.tenant.core.job.TenantJobAspect
;
import
cn.iocoder.yudao.framework.tenant.core.mq.TenantChannelInterceptor
;
import
cn.iocoder.yudao.framework.tenant.core.mq.TenantFunctionAroundWrapper
;
import
cn.iocoder.yudao.framework.tenant.core.security.TenantSecurityWebFilter
;
...
...
@@ -19,6 +16,7 @@ import cn.iocoder.yudao.framework.web.core.handler.GlobalExceptionHandler;
import
cn.iocoder.yudao.module.system.api.tenant.TenantApi
;
import
com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor
;
import
com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor
;
import
com.xxl.job.core.executor.XxlJobExecutor
;
import
org.springframework.beans.BeansException
;
import
org.springframework.beans.factory.config.BeanPostProcessor
;
import
org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
;
...
...
@@ -103,19 +101,25 @@ public class YudaoTenantAutoConfiguration {
@Override
public
Object
postProcessBeforeInitialization
(
Object
bean
,
String
beanName
)
throws
BeansException
{
if
(!(
bean
instanceof
JobHandle
r
))
{
if
(!(
bean
instanceof
XxlJobExecuto
r
))
{
return
bean
;
}
// 有 TenantJob 注解的情况下,才会进行处理
if
(!
AnnotationUtil
.
hasAnnotation
(
bean
.
getClass
(),
TenantJob
.
class
))
{
return
bean
;
}
// 使用 TenantJobHandlerDecorator 装饰
return
new
TenantJobHandlerDecorator
(
tenantFrameworkService
,
(
JobHandler
)
bean
);
// // 有 TenantJob 注解的情况下,才会进行处理
// if (!AnnotationUtil.hasAnnotation(bean.getClass(), TenantJob.class)) {
// return bean;
// }
//
// // 使用 TenantJobHandlerDecorator 装饰
// return new TenantJobHandlerDecorator(tenantFrameworkService, (JobHandler) bean);
return
bean
;
}
};
}
@Bean
public
TenantJobAspect
tenantJobAspect
(
TenantFrameworkService
tenantFrameworkService
)
{
return
new
TenantJobAspect
(
tenantFrameworkService
);
}
}
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/job/TenantJobAspect.java
0 → 100644
浏览文件 @
3774afe5
package
cn
.
iocoder
.
yudao
.
framework
.
tenant
.
core
.
job
;
import
cn.hutool.core.collection.CollUtil
;
import
cn.hutool.core.exceptions.ExceptionUtil
;
import
cn.hutool.core.util.StrUtil
;
import
cn.iocoder.yudao.framework.common.util.json.JsonUtils
;
import
cn.iocoder.yudao.framework.tenant.core.service.TenantFrameworkService
;
import
cn.iocoder.yudao.framework.tenant.core.util.TenantUtils
;
import
com.xxl.job.core.context.XxlJobHelper
;
import
com.xxl.job.core.handler.annotation.XxlJob
;
import
lombok.RequiredArgsConstructor
;
import
lombok.extern.slf4j.Slf4j
;
import
org.apache.commons.lang3.exception.ExceptionUtils
;
import
org.aspectj.lang.ProceedingJoinPoint
;
import
org.aspectj.lang.annotation.Around
;
import
org.aspectj.lang.annotation.Aspect
;
import
org.aspectj.lang.reflect.MethodSignature
;
import
java.lang.annotation.Annotation
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.concurrent.ConcurrentHashMap
;
@Aspect
@RequiredArgsConstructor
@Slf4j
public
class
TenantJobAspect
{
private
final
TenantFrameworkService
tenantFrameworkService
;
@Around
(
"@annotation(xxlJob)"
)
public
Object
around
(
ProceedingJoinPoint
joinPoint
,
XxlJob
xxlJob
)
throws
Throwable
{
// 如果非多租户 Job,则跳过
TenantJob
tenantJob
=
getClassAnnotation
(
joinPoint
,
TenantJob
.
class
);
if
(
tenantJob
==
null
)
{
return
joinPoint
.
proceed
();
}
// 如果是多租户 Job,则会按照租户逐个执行 Job 的逻辑
execute
(
joinPoint
,
xxlJob
);
return
null
;
// JobHandler 无返回
}
private
void
execute
(
ProceedingJoinPoint
joinPoint
,
XxlJob
xxlJob
)
{
// 获得租户列表
List
<
Long
>
tenantIds
=
tenantFrameworkService
.
getTenantIds
();
if
(
CollUtil
.
isEmpty
(
tenantIds
))
{
return
;
}
// 逐个租户,执行 Job
Map
<
Long
,
String
>
results
=
new
ConcurrentHashMap
<>();
tenantIds
.
parallelStream
().
forEach
(
tenantId
->
{
// TODO 芋艿:先通过 parallel 实现并行;1)多个租户,是一条执行日志;2)异常的情况
TenantUtils
.
execute
(
tenantId
,
()
->
{
try
{
joinPoint
.
proceed
();
}
catch
(
Throwable
e
)
{
results
.
put
(
tenantId
,
ExceptionUtil
.
getRootCauseMessage
(
e
));
// 打印异常
XxlJobHelper
.
log
(
StrUtil
.
format
(
"[多租户({}) 执行任务({}),发生异常:{}]"
,
tenantId
,
xxlJob
.
value
(),
ExceptionUtils
.
getStackTrace
(
e
)));
}
});
});
// 如果 results 非空,说明发生了异常,标记 XXL-Job 执行失败
if
(
CollUtil
.
isNotEmpty
(
results
))
{
XxlJobHelper
.
handleFail
(
JsonUtils
.
toJsonString
(
results
));
}
}
@SuppressWarnings
(
"SameParameterValue"
)
private
static
<
T
extends
Annotation
>
T
getClassAnnotation
(
ProceedingJoinPoint
joinPoint
,
Class
<
T
>
annotationClass
)
{
return
((
MethodSignature
)
joinPoint
.
getSignature
()).
getMethod
().
getDeclaringClass
().
getAnnotation
(
annotationClass
);
}
}
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/job/TenantJobHandlerDecorator.java
deleted
100644 → 0
浏览文件 @
4381d938
package
cn
.
iocoder
.
yudao
.
framework
.
tenant
.
core
.
job
;
import
cn.hutool.core.collection.CollUtil
;
import
cn.iocoder.yudao.framework.common.util.json.JsonUtils
;
import
cn.iocoder.yudao.framework.quartz.core.handler.JobHandler
;
import
cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder
;
import
cn.iocoder.yudao.framework.tenant.core.service.TenantFrameworkService
;
import
lombok.AllArgsConstructor
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.concurrent.ConcurrentHashMap
;
/**
* 多租户 JobHandler 装饰器
* 任务执行时,会按照租户逐个执行 Job 的逻辑
*
* 注意,需要保证 JobHandler 的幂等性。因为 Job 因为某个租户执行失败重试时,之前执行成功的租户也会再次执行。
*
* @author 芋道源码
*/
@AllArgsConstructor
public
class
TenantJobHandlerDecorator
implements
JobHandler
{
private
final
TenantFrameworkService
tenantFrameworkService
;
/**
* 被装饰的 Job
*/
private
final
JobHandler
jobHandler
;
@Override
public
final
String
execute
(
String
param
)
throws
Exception
{
// 获得租户列表
List
<
Long
>
tenantIds
=
tenantFrameworkService
.
getTenantIds
();
if
(
CollUtil
.
isEmpty
(
tenantIds
))
{
return
null
;
}
// 逐个租户,执行 Job
Map
<
Long
,
String
>
results
=
new
ConcurrentHashMap
<>();
tenantIds
.
parallelStream
().
forEach
(
tenantId
->
{
// TODO 芋艿:先通过 parallel 实现并行;1)多个租户,是一条执行日志;2)异常的情况
try
{
// 设置租户
TenantContextHolder
.
setTenantId
(
tenantId
);
// 执行 Job
String
result
=
jobHandler
.
execute
(
param
);
// 添加结果
results
.
put
(
tenantId
,
result
);
}
catch
(
Exception
e
)
{
throw
new
RuntimeException
(
e
);
}
finally
{
TenantContextHolder
.
clear
();
}
});
return
JsonUtils
.
toJsonString
(
results
);
}
}
yudao-framework/yudao-spring-boot-starter-job/pom.xml
浏览文件 @
3774afe5
...
...
@@ -12,10 +12,7 @@
<packaging>
jar
</packaging>
<name>
${project.artifactId}
</name>
<description>
任务拓展
1. 定时任务,基于 Quartz 拓展
2. 异步任务,基于 Spring Async 拓展
</description>
<description>
任务拓展,基于 XXL-Job 实现
</description>
<url>
https://github.com/YunaiV/ruoyi-vue-pro
</url>
<dependencies>
...
...
@@ -24,10 +21,22 @@
<artifactId>
yudao-common
</artifactId>
</dependency>
<!--
Job 定时任务相关
-->
<!--
Spring 核心
-->
<dependency>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-starter-quartz
</artifactId>
<artifactId>
spring-boot-configuration-processor
</artifactId>
<optional>
true
</optional>
</dependency>
<dependency>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-starter
</artifactId>
<optional>
true
</optional>
</dependency>
<!-- Job 相关 -->
<dependency>
<groupId>
com.xuxueli
</groupId>
<artifactId>
xxl-job-core
</artifactId>
</dependency>
<!-- 工具类相关 -->
...
...
归档/common/mall-spring-boot-starter-xxl-job/src/main/java/cn/iocoder/mall/xxljob
/config/XxlJobProperties.java
→
yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz
/config/XxlJobProperties.java
浏览文件 @
3774afe5
package
cn
.
iocoder
.
mall
.
xxljob
.
config
;
package
cn
.
iocoder
.
yudao
.
framework
.
quartz
.
config
;
import
lombok.Data
;
import
org.springframework.boot.context.properties.ConfigurationProperties
;
import
org.springframework.validation.annotation.Validated
;
import
javax.validation.Valid
;
import
javax.validation.constraints.NotEmpty
;
import
javax.validation.constraints.NotNull
;
/**
* XXL-Job 配置类
*/
@ConfigurationProperties
(
"xxl.job"
)
@Validated
@Data
public
class
XxlJobProperties
{
/**
...
...
@@ -19,78 +27,34 @@ public class XxlJobProperties {
/**
* 控制器配置
*/
@NotNull
(
message
=
"控制器配置不能为空"
)
private
AdminProperties
admin
;
/**
* 执行器配置
*/
@NotNull
(
message
=
"执行器配置不能为空"
)
private
ExecutorProperties
executor
;
public
Boolean
getEnabled
()
{
return
enabled
;
}
public
void
setEnabled
(
Boolean
enabled
)
{
if
(
enabled
!=
null
)
{
this
.
enabled
=
enabled
;
}
}
public
String
getAccessToken
()
{
return
accessToken
;
}
public
void
setAccessToken
(
String
accessToken
)
{
if
(
accessToken
!=
null
&&
accessToken
.
trim
().
length
()
>
0
)
{
this
.
accessToken
=
accessToken
;
}
}
public
AdminProperties
getAdmin
()
{
return
admin
;
}
public
void
setAdmin
(
AdminProperties
admin
)
{
this
.
admin
=
admin
;
}
public
ExecutorProperties
getExecutor
()
{
return
executor
;
}
public
void
setExecutor
(
ExecutorProperties
executor
)
{
this
.
executor
=
executor
;
}
/**
* XXL-Job 调度器配置类
*/
@Data
@Valid
public
static
class
AdminProperties
{
/**
* 调度器地址
*/
@NotEmpty
(
message
=
"调度器地址不能为空"
)
private
String
addresses
;
public
String
getAddresses
()
{
return
addresses
;
}
public
void
setAddresses
(
String
addresses
)
{
this
.
addresses
=
addresses
;
}
@Override
public
String
toString
()
{
return
"AdminProperties{"
+
"addresses='"
+
addresses
+
'\''
+
'}'
;
}
}
/**
* XXL-Job 执行器配置类
*/
@Data
@Valid
public
static
class
ExecutorProperties
{
/**
...
...
@@ -103,13 +67,14 @@ public class XxlJobProperties {
/**
* 默认日志保留天数
*
*
默认为 -1,不清理,永久保留
*
如果想永久保留,则设置为 -1
*/
private
static
final
Integer
LOG_RETENTION_DAYS_DEFAULT
=
-
1
;
private
static
final
Integer
LOG_RETENTION_DAYS_DEFAULT
=
30
;
/**
* 应用名
*/
@NotEmpty
(
message
=
"应用名不能为空"
)
private
String
appName
;
/**
* 执行器的 IP
...
...
@@ -122,51 +87,13 @@ public class XxlJobProperties {
/**
* 日志地址
*/
@NotEmpty
(
message
=
"日志地址不能为空"
)
private
String
logPath
;
/**
* 日志保留天数
*/
private
Integer
logRetentionDays
=
LOG_RETENTION_DAYS_DEFAULT
;
public
String
getAppName
()
{
return
appName
;
}
public
void
setAppName
(
String
appName
)
{
this
.
appName
=
appName
;
}
public
String
getLogPath
()
{
return
logPath
;
}
public
void
setLogPath
(
String
logPath
)
{
this
.
logPath
=
logPath
;
}
public
String
getIp
()
{
return
ip
;
}
public
void
setIp
(
String
ip
)
{
this
.
ip
=
ip
;
}
public
Integer
getPort
()
{
return
port
;
}
public
void
setPort
(
Integer
port
)
{
this
.
port
=
port
;
}
public
Integer
getLogRetentionDays
()
{
return
logRetentionDays
;
}
public
void
setLogRetentionDays
(
Integer
logRetentionDays
)
{
this
.
logRetentionDays
=
logRetentionDays
;
}
}
}
yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/config/YudaoQuartzAutoConfiguration.java
deleted
100644 → 0
浏览文件 @
4381d938
package
cn
.
iocoder
.
yudao
.
framework
.
quartz
.
config
;
import
cn.iocoder.yudao.framework.quartz.core.scheduler.SchedulerManager
;
import
org.quartz.Scheduler
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.scheduling.annotation.EnableScheduling
;
/**
* 定时任务 Configuration
*/
@Configuration
@EnableScheduling
// 开启 Spring 自带的定时任务
public
class
YudaoQuartzAutoConfiguration
{
@Bean
public
SchedulerManager
schedulerManager
(
Scheduler
scheduler
)
{
return
new
SchedulerManager
(
scheduler
);
}
}
归档/common/mall-spring-boot-starter-xxl-job/src/main/java/cn/iocoder/mall/xxljob/config/
XxlJobAutoConfiguration.java
→
yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/config/Yudao
XxlJobAutoConfiguration.java
浏览文件 @
3774afe5
package
cn
.
iocoder
.
mall
.
xxljob
.
config
;
package
cn
.
iocoder
.
yudao
.
framework
.
quartz
.
config
;
import
com.xxl.job.core.executor.XxlJobExecutor
;
import
com.xxl.job.core.executor.impl.XxlJobSpringExecutor
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.boot.autoconfigure.condition.ConditionalOnClass
;
import
org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
;
import
org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
;
import
org.springframework.boot.context.properties.EnableConfigurationProperties
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Configuration
;
import
java.util.Objects
;
import
org.springframework.scheduling.annotation.EnableScheduling
;
/**
* XXL-Job 自动配置类
*
* @author 芋道源码
*/
@Configuration
@ConditionalOnClass
(
XxlJobSpringExecutor
.
class
)
@ConditionalOnProperty
(
prefix
=
"xxl.job"
,
name
=
"enabled"
,
havingValue
=
"true"
,
matchIfMissing
=
true
)
@EnableConfigurationProperties
({
XxlJobProperties
.
class
})
public
class
XxlJobAutoConfiguration
{
private
static
final
Logger
LOGGER
=
LoggerFactory
.
getLogger
(
XxlJobAutoConfiguration
.
class
);
private
final
XxlJobProperties
properties
;
public
XxlJobAutoConfiguration
(
XxlJobProperties
properties
)
{
this
.
properties
=
properties
;
}
@EnableScheduling
// 开启 Spring 自带的定时任务
@Slf4j
public
class
YudaoXxlJobAutoConfiguration
{
@Bean
@ConditionalOnMissingBean
public
XxlJobExecutor
xxlJobExecutor
()
{
LOGGER
.
info
(
"初始化 XXL-Job 执行器的配置"
);
// 参数校验
XxlJobProperties
.
AdminProperties
admin
=
this
.
properties
.
getAdmin
();
XxlJobProperties
.
ExecutorProperties
executor
=
this
.
properties
.
getExecutor
();
Objects
.
requireNonNull
(
admin
,
"xxl job admin properties must not be null."
);
Objects
.
requireNonNull
(
executor
,
"xxl job executor properties must not be null."
);
public
XxlJobExecutor
xxlJobExecutor
(
XxlJobProperties
properties
)
{
log
.
info
(
"[xxlJobExecutor][初始化 XXL-Job 执行器的配置]"
);
XxlJobProperties
.
AdminProperties
admin
=
properties
.
getAdmin
();
XxlJobProperties
.
ExecutorProperties
executor
=
properties
.
getExecutor
();
// 初始化执行器
XxlJobExecutor
xxlJobExecutor
=
new
XxlJobSpringExecutor
();
...
...
@@ -49,7 +39,7 @@ public class XxlJobAutoConfiguration {
xxlJobExecutor
.
setLogPath
(
executor
.
getLogPath
());
xxlJobExecutor
.
setLogRetentionDays
(
executor
.
getLogRetentionDays
());
xxlJobExecutor
.
setAdminAddresses
(
admin
.
getAddresses
());
xxlJobExecutor
.
setAccessToken
(
this
.
properties
.
getAccessToken
());
xxlJobExecutor
.
setAccessToken
(
properties
.
getAccessToken
());
return
xxlJobExecutor
;
}
...
...
yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/core/enums/JobDataKeyEnum.java
deleted
100644 → 0
浏览文件 @
4381d938
package
cn
.
iocoder
.
yudao
.
framework
.
quartz
.
core
.
enums
;
/**
* Quartz Job Data 的 key 枚举
*/
public
enum
JobDataKeyEnum
{
JOB_ID
,
JOB_HANDLER_NAME
,
JOB_HANDLER_PARAM
,
JOB_RETRY_COUNT
,
// 最大重试次数
JOB_RETRY_INTERVAL
,
// 每次重试间隔
}
yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/core/handler/JobHandler.java
deleted
100644 → 0
浏览文件 @
4381d938
package
cn
.
iocoder
.
yudao
.
framework
.
quartz
.
core
.
handler
;
/**
* 任务处理器
*
* @author 芋道源码
*/
public
interface
JobHandler
{
/**
* 执行任务
*
* @param param 参数
* @return 结果
* @throws Exception 异常
*/
String
execute
(
String
param
)
throws
Exception
;
}
yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/core/handler/JobHandlerInvoker.java
deleted
100644 → 0
浏览文件 @
4381d938
package
cn
.
iocoder
.
yudao
.
framework
.
quartz
.
core
.
handler
;
import
cn.hutool.core.lang.Assert
;
import
cn.hutool.core.thread.ThreadUtil
;
import
cn.iocoder.yudao.framework.quartz.core.enums.JobDataKeyEnum
;
import
cn.iocoder.yudao.framework.quartz.core.service.JobLogFrameworkService
;
import
lombok.extern.slf4j.Slf4j
;
import
org.quartz.DisallowConcurrentExecution
;
import
org.quartz.JobExecutionContext
;
import
org.quartz.JobExecutionException
;
import
org.quartz.PersistJobDataAfterExecution
;
import
org.springframework.context.ApplicationContext
;
import
org.springframework.scheduling.quartz.QuartzJobBean
;
import
javax.annotation.Resource
;
import
java.util.Date
;
import
static
cn
.
hutool
.
core
.
exceptions
.
ExceptionUtil
.
getRootCauseMessage
;
import
static
cn
.
iocoder
.
yudao
.
framework
.
common
.
util
.
date
.
DateUtils
.
diff
;
/**
* 基础 Job 调用者,负责调用 {@link JobHandler#execute(String)} 执行任务
*
* @author 芋道源码
*/
@DisallowConcurrentExecution
@PersistJobDataAfterExecution
@Slf4j
public
class
JobHandlerInvoker
extends
QuartzJobBean
{
@Resource
private
ApplicationContext
applicationContext
;
@Resource
private
JobLogFrameworkService
jobLogFrameworkService
;
@Override
protected
void
executeInternal
(
JobExecutionContext
executionContext
)
throws
JobExecutionException
{
// 第一步,获得 Job 数据
Long
jobId
=
executionContext
.
getMergedJobDataMap
().
getLong
(
JobDataKeyEnum
.
JOB_ID
.
name
());
String
jobHandlerName
=
executionContext
.
getMergedJobDataMap
().
getString
(
JobDataKeyEnum
.
JOB_HANDLER_NAME
.
name
());
String
jobHandlerParam
=
executionContext
.
getMergedJobDataMap
().
getString
(
JobDataKeyEnum
.
JOB_HANDLER_PARAM
.
name
());
int
refireCount
=
executionContext
.
getRefireCount
();
int
retryCount
=
(
Integer
)
executionContext
.
getMergedJobDataMap
().
getOrDefault
(
JobDataKeyEnum
.
JOB_RETRY_COUNT
.
name
(),
0
);
int
retryInterval
=
(
Integer
)
executionContext
.
getMergedJobDataMap
().
getOrDefault
(
JobDataKeyEnum
.
JOB_RETRY_INTERVAL
.
name
(),
0
);
// 第二步,执行任务
Long
jobLogId
=
null
;
Date
startTime
=
new
Date
();
String
data
=
null
;
Throwable
exception
=
null
;
try
{
// 记录 Job 日志(初始)
jobLogId
=
jobLogFrameworkService
.
createJobLog
(
jobId
,
startTime
,
jobHandlerName
,
jobHandlerParam
,
refireCount
+
1
);
// 执行任务
data
=
this
.
executeInternal
(
jobHandlerName
,
jobHandlerParam
);
}
catch
(
Throwable
ex
)
{
exception
=
ex
;
}
// 第三步,记录执行日志
this
.
updateJobLogResultAsync
(
jobLogId
,
startTime
,
data
,
exception
,
executionContext
);
// 第四步,处理有异常的情况
handleException
(
exception
,
refireCount
,
retryCount
,
retryInterval
);
}
private
String
executeInternal
(
String
jobHandlerName
,
String
jobHandlerParam
)
throws
Exception
{
// 获得 JobHandler 对象
JobHandler
jobHandler
=
applicationContext
.
getBean
(
jobHandlerName
,
JobHandler
.
class
);
Assert
.
notNull
(
jobHandler
,
"JobHandler 不会为空"
);
// 执行任务
return
jobHandler
.
execute
(
jobHandlerParam
);
}
private
void
updateJobLogResultAsync
(
Long
jobLogId
,
Date
startTime
,
String
data
,
Throwable
exception
,
JobExecutionContext
executionContext
)
{
Date
endTime
=
new
Date
();
// 处理是否成功
boolean
success
=
exception
==
null
;
if
(!
success
)
{
data
=
getRootCauseMessage
(
exception
);
}
// 更新日志
try
{
jobLogFrameworkService
.
updateJobLogResultAsync
(
jobLogId
,
endTime
,
(
int
)
diff
(
endTime
,
startTime
),
success
,
data
);
}
catch
(
Exception
ex
)
{
log
.
error
(
"[executeInternal][Job({}) logId({}) 记录执行日志失败({}/{})]"
,
executionContext
.
getJobDetail
().
getKey
(),
jobLogId
,
success
,
data
);
}
}
private
void
handleException
(
Throwable
exception
,
int
refireCount
,
int
retryCount
,
int
retryInterval
)
throws
JobExecutionException
{
// 如果有异常,则进行重试
if
(
exception
==
null
)
{
return
;
}
// 情况一:如果到达重试上限,则直接抛出异常即可
if
(
refireCount
>=
retryCount
)
{
throw
new
JobExecutionException
(
exception
);
}
// 情况二:如果未到达重试上限,则 sleep 一定间隔时间,然后重试
// 这里使用 sleep 来实现,主要还是希望实现比较简单。因为,同一时间,不会存在大量失败的 Job。
if
(
retryInterval
>
0
)
{
ThreadUtil
.
sleep
(
retryInterval
);
}
// 第二个参数,refireImmediately = true,表示立即重试
throw
new
JobExecutionException
(
exception
,
true
);
}
}
yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/core/scheduler/SchedulerManager.java
deleted
100644 → 0
浏览文件 @
4381d938
package
cn
.
iocoder
.
yudao
.
framework
.
quartz
.
core
.
scheduler
;
import
cn.iocoder.yudao.framework.quartz.core.enums.JobDataKeyEnum
;
import
cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker
;
import
org.quartz.*
;
/**
* {@link org.quartz.Scheduler} 的管理器,负责创建任务
*
* 考虑到实现的简洁性,我们使用 jobHandlerName 作为唯一标识,即:
* 1. Job 的 {@link JobDetail#getKey()}
* 2. Trigger 的 {@link Trigger#getKey()}
*
* 另外,jobHandlerName 对应到 Spring Bean 的名字,直接调用
*
* @author 芋道源码
*/
public
class
SchedulerManager
{
private
final
Scheduler
scheduler
;
public
SchedulerManager
(
Scheduler
scheduler
)
{
this
.
scheduler
=
scheduler
;
}
/**
* 添加 Job 到 Quartz 中
*
* @param jobId 任务编号
* @param jobHandlerName 任务处理器的名字
* @param jobHandlerParam 任务处理器的参数
* @param cronExpression CRON 表达式
* @param retryCount 重试次数
* @param retryInterval 重试间隔
* @throws SchedulerException 添加异常
*/
public
void
addJob
(
Long
jobId
,
String
jobHandlerName
,
String
jobHandlerParam
,
String
cronExpression
,
Integer
retryCount
,
Integer
retryInterval
)
throws
SchedulerException
{
// 创建 JobDetail 对象
JobDetail
jobDetail
=
JobBuilder
.
newJob
(
JobHandlerInvoker
.
class
)
.
usingJobData
(
JobDataKeyEnum
.
JOB_ID
.
name
(),
jobId
)
.
usingJobData
(
JobDataKeyEnum
.
JOB_HANDLER_NAME
.
name
(),
jobHandlerName
)
.
withIdentity
(
jobHandlerName
).
build
();
// 创建 Trigger 对象
Trigger
trigger
=
this
.
buildTrigger
(
jobHandlerName
,
jobHandlerParam
,
cronExpression
,
retryCount
,
retryInterval
);
// 新增调度
scheduler
.
scheduleJob
(
jobDetail
,
trigger
);
}
/**
* 更新 Job 到 Quartz
*
* @param jobHandlerName 任务处理器的名字
* @param jobHandlerParam 任务处理器的参数
* @param cronExpression CRON 表达式
* @param retryCount 重试次数
* @param retryInterval 重试间隔
* @throws SchedulerException 更新异常
*/
public
void
updateJob
(
String
jobHandlerName
,
String
jobHandlerParam
,
String
cronExpression
,
Integer
retryCount
,
Integer
retryInterval
)
throws
SchedulerException
{
// 创建新 Trigger 对象
Trigger
newTrigger
=
this
.
buildTrigger
(
jobHandlerName
,
jobHandlerParam
,
cronExpression
,
retryCount
,
retryInterval
);
// 修改调度
scheduler
.
rescheduleJob
(
new
TriggerKey
(
jobHandlerName
),
newTrigger
);
}
/**
* 删除 Quartz 中的 Job
*
* @param jobHandlerName 任务处理器的名字
* @throws SchedulerException 删除异常
*/
public
void
deleteJob
(
String
jobHandlerName
)
throws
SchedulerException
{
scheduler
.
deleteJob
(
new
JobKey
(
jobHandlerName
));
}
/**
* 暂停 Quartz 中的 Job
*
* @param jobHandlerName 任务处理器的名字
* @throws SchedulerException 暂停异常
*/
public
void
pauseJob
(
String
jobHandlerName
)
throws
SchedulerException
{
scheduler
.
pauseJob
(
new
JobKey
(
jobHandlerName
));
}
/**
* 启动 Quartz 中的 Job
*
* @param jobHandlerName 任务处理器的名字
* @throws SchedulerException 启动异常
*/
public
void
resumeJob
(
String
jobHandlerName
)
throws
SchedulerException
{
scheduler
.
resumeJob
(
new
JobKey
(
jobHandlerName
));
scheduler
.
resumeTrigger
(
new
TriggerKey
(
jobHandlerName
));
}
/**
* 立即触发一次 Quartz 中的 Job
*
* @param jobId 任务编号
* @param jobHandlerName 任务处理器的名字
* @param jobHandlerParam 任务处理器的参数
* @throws SchedulerException 触发异常
*/
public
void
triggerJob
(
Long
jobId
,
String
jobHandlerName
,
String
jobHandlerParam
)
throws
SchedulerException
{
JobDataMap
data
=
new
JobDataMap
();
// 无需重试,所以不设置 retryCount 和 retryInterval
data
.
put
(
JobDataKeyEnum
.
JOB_ID
.
name
(),
jobId
);
data
.
put
(
JobDataKeyEnum
.
JOB_HANDLER_NAME
.
name
(),
jobHandlerName
);
data
.
put
(
JobDataKeyEnum
.
JOB_HANDLER_PARAM
.
name
(),
jobHandlerParam
);
// 触发任务
scheduler
.
triggerJob
(
new
JobKey
(
jobHandlerName
),
data
);
}
private
Trigger
buildTrigger
(
String
jobHandlerName
,
String
jobHandlerParam
,
String
cronExpression
,
Integer
retryCount
,
Integer
retryInterval
)
{
return
TriggerBuilder
.
newTrigger
()
.
withIdentity
(
jobHandlerName
)
.
withSchedule
(
CronScheduleBuilder
.
cronSchedule
(
cronExpression
))
.
usingJobData
(
JobDataKeyEnum
.
JOB_HANDLER_PARAM
.
name
(),
jobHandlerParam
)
.
usingJobData
(
JobDataKeyEnum
.
JOB_RETRY_COUNT
.
name
(),
retryCount
)
.
usingJobData
(
JobDataKeyEnum
.
JOB_RETRY_INTERVAL
.
name
(),
retryInterval
)
.
build
();
}
}
yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/core/service/JobLogFrameworkService.java
deleted
100644 → 0
浏览文件 @
4381d938
package
cn
.
iocoder
.
yudao
.
framework
.
quartz
.
core
.
service
;
import
javax.validation.constraints.NotEmpty
;
import
javax.validation.constraints.NotNull
;
import
java.util.Date
;
/**
* Job 日志 Framework Service 接口
*
* @author 芋道源码
*/
public
interface
JobLogFrameworkService
{
/**
* 创建 Job 日志
*
* @param jobId 任务编号
* @param beginTime 开始时间
* @param jobHandlerName Job 处理器的名字
* @param jobHandlerParam Job 处理器的参数
* @param executeIndex 第几次执行
* @return Job 日志的编号
*/
Long
createJobLog
(
@NotNull
(
message
=
"任务编号不能为空"
)
Long
jobId
,
@NotNull
(
message
=
"开始时间"
)
Date
beginTime
,
@NotEmpty
(
message
=
"Job 处理器的名字不能为空"
)
String
jobHandlerName
,
String
jobHandlerParam
,
@NotNull
(
message
=
"第几次执行不能为空"
)
Integer
executeIndex
);
/**
* 更新 Job 日志的执行结果
*
* @param logId 日志编号
* @param endTime 结束时间。因为是异步,避免记录时间不准去
* @param duration 运行时长,单位:毫秒
* @param success 是否成功
* @param result 成功数据
*/
void
updateJobLogResultAsync
(
@NotNull
(
message
=
"日志编号不能为空"
)
Long
logId
,
@NotNull
(
message
=
"结束时间不能为空"
)
Date
endTime
,
@NotNull
(
message
=
"运行时长不能为空"
)
Integer
duration
,
boolean
success
,
String
result
);
}
yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/core/util/CronUtils.java
deleted
100644 → 0
浏览文件 @
4381d938
package
cn
.
iocoder
.
yudao
.
framework
.
quartz
.
core
.
util
;
import
org.quartz.CronExpression
;
import
java.text.ParseException
;
import
java.util.ArrayList
;
import
java.util.Date
;
import
java.util.List
;
/**
* Quartz Cron 表达式的工具类
*
* @author 芋道源码
*/
public
class
CronUtils
{
/**
* 校验 CRON 表达式是否有效
*
* @param cronExpression CRON 表达式
* @return 是否有效
*/
public
static
boolean
isValid
(
String
cronExpression
)
{
return
CronExpression
.
isValidExpression
(
cronExpression
);
}
/**
* 基于 CRON 表达式,获得下 n 个满足执行的时间
*
* @param cronExpression CRON 表达式
* @param n 数量
* @return 满足条件的执行时间
*/
public
static
List
<
Date
>
getNextTimes
(
String
cronExpression
,
int
n
)
{
// 获得 CronExpression 对象
CronExpression
cron
;
try
{
cron
=
new
CronExpression
(
cronExpression
);
}
catch
(
ParseException
e
)
{
throw
new
IllegalArgumentException
(
e
.
getMessage
());
}
// 从当前开始计算,n 个满足条件的
Date
now
=
new
Date
();
List
<
Date
>
nextTimes
=
new
ArrayList
<>(
n
);
for
(
int
i
=
0
;
i
<
n
;
i
++)
{
Date
nextTime
=
cron
.
getNextValidTimeAfter
(
now
);
nextTimes
.
add
(
nextTime
);
// 切换现在,为下一个触发时间;
now
=
nextTime
;
}
return
nextTimes
;
}
}
yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/package-info.java
浏览文件 @
3774afe5
/**
* 1. 定时任务,采用 Quartz 实现进程内的任务执行。
* 考虑到高可用,使用 Quartz 自带的 MySQL 集群方案。
*
* 1. 定时任务,基于 XXL-Job 实现。
* 2. 异步任务,采用 Spring Async 异步执行。
*/
package
cn
.
iocoder
.
yudao
.
framework
.
quartz
;
yudao-framework/yudao-spring-boot-starter-job/src/main/resources/META-INF/spring.factories
浏览文件 @
3774afe5
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
cn.iocoder.yudao.framework.quartz.config.Yudao
Quartz
AutoConfiguration,\
cn.iocoder.yudao.framework.quartz.config.Yudao
XxlJob
AutoConfiguration,\
cn.iocoder.yudao.framework.quartz.config.YudaoAsyncAutoConfiguration
yudao-module-infra/yudao-module-infra-biz/pom.xml
浏览文件 @
3774afe5
...
...
@@ -94,11 +94,11 @@
<artifactId>
spring-cloud-starter-alibaba-nacos-config
</artifactId>
</dependency>
<!-- Job 定时任务相关
TODO 芋艿:暂时去掉
-->
<!-- <dependency>--
>
<!-- <groupId>cn.iocoder.cloud</groupId>--
>
<!-- <artifactId>yudao-spring-boot-starter-job</artifactId>--
>
<!-- </dependency>--
>
<!-- Job 定时任务相关 -->
<dependency
>
<groupId>
cn.iocoder.cloud
</groupId
>
<artifactId>
yudao-spring-boot-starter-job
</artifactId
>
</dependency
>
<!-- 消息队列相关 -->
<dependency>
...
...
yudao-module-infra/yudao-module-infra-biz/src/main/resources/application-dev.yaml
浏览文件 @
3774afe5
...
...
@@ -72,8 +72,10 @@ spring:
name-server
:
127.0.0.1:9876
# RocketMQ Namesrv 地址
---
#################### 定时任务相关配置 ####################
---
#################### 配置中心相关配置 ####################
xxl
:
job
:
admin
:
addresses
:
http://127.0.0.1:9090/xxl-job-admin
# 调度中心部署跟地址
---
#################### 服务保障相关配置 ####################
...
...
yudao-module-infra/yudao-module-infra-biz/src/main/resources/application-local.yaml
浏览文件 @
3774afe5
...
...
@@ -83,8 +83,10 @@ spring:
name-server
:
127.0.0.1:9876
# RocketMQ Namesrv 地址
---
#################### 定时任务相关配置 ####################
---
#################### 配置中心相关配置 ####################
xxl
:
job
:
admin
:
addresses
:
http://127.0.0.1:9090/xxl-job-admin
# 调度中心部署跟地址
---
#################### 服务保障相关配置 ####################
...
...
yudao-module-infra/yudao-module-infra-biz/src/main/resources/application.yaml
浏览文件 @
3774afe5
...
...
@@ -84,6 +84,15 @@ spring:
id
:
${spring.application.name}:${server.port}
# 编号,Spring Cloud Alibaba 建议使用“应用:端口”的格式
destination
:
springCloudBus
# 目标消息队列,默认为 springCloudBus
---
#################### 定时任务相关配置 ####################
xxl
:
job
:
executor
:
appname
:
${spring.application.name}
# 执行器 AppName
logpath
:
${user.home}/logs/xxl-job/${spring.application.name}
# 执行器运行日志文件存储磁盘路径
accessToken
:
default_token
# 执行器通讯TOKEN
---
#################### 芋道相关配置 ####################
yudao
:
...
...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/job/demo/DemoJob.java
0 → 100644
浏览文件 @
3774afe5
package
cn
.
iocoder
.
yudao
.
module
.
system
.
job
.
demo
;
import
cn.iocoder.yudao.framework.tenant.core.job.TenantJob
;
import
com.xxl.job.core.handler.annotation.XxlJob
;
import
org.springframework.stereotype.Component
;
@Component
@TenantJob
public
class
DemoJob
{
@XxlJob
(
"demoJob"
)
public
void
execute
()
{
System
.
out
.
println
(
"美滋滋"
);
}
}
yudao-module-system/yudao-module-system-biz/src/main/resources/application-dev.yaml
浏览文件 @
3774afe5
...
...
@@ -72,6 +72,10 @@ spring:
name-server
:
127.0.0.1:9876
# RocketMQ Namesrv 地址
---
#################### 定时任务相关配置 ####################
xxl
:
job
:
admin
:
addresses
:
http://127.0.0.1:9090/xxl-job-admin
# 调度中心部署跟地址
---
#################### 服务保障相关配置 ####################
...
...
yudao-module-system/yudao-module-system-biz/src/main/resources/application-local.yaml
浏览文件 @
3774afe5
...
...
@@ -83,6 +83,11 @@ spring:
---
#################### 定时任务相关配置 ####################
xxl
:
job
:
admin
:
addresses
:
http://127.0.0.1:9090/xxl-job-admin
# 调度中心部署跟地址
---
#################### 服务保障相关配置 ####################
# Lock4j 配置项
...
...
yudao-module-system/yudao-module-system-biz/src/main/resources/application.yaml
浏览文件 @
3774afe5
...
...
@@ -82,6 +82,15 @@ spring:
id
:
${spring.application.name}:${server.port}
# 编号,Spring Cloud Alibaba 建议使用“应用:端口”的格式
destination
:
springCloudBus
# 目标消息队列,默认为 springCloudBus
---
#################### 定时任务相关配置 ####################
xxl
:
job
:
executor
:
appname
:
${spring.application.name}
# 执行器 AppName
logpath
:
${user.home}/logs/xxl-job/${spring.application.name}
# 执行器运行日志文件存储磁盘路径
accessToken
:
default_token
# 执行器通讯TOKEN
---
#################### 芋道相关配置 ####################
yudao
:
...
...
@@ -110,6 +119,7 @@ yudao:
-
/admin-api/system/captcha/get-image
# 获取图片验证码,和租户无关
-
/admin-api/system/sms/callback/*
# 短信回调接口,无法带上租户编号
-
/rpc-api/system/tenant/valid
# 防止递归。避免调用 /rpc-api/system/tenant/valid 接口时,又去触发 /rpc-api/system/tenant/valid 去校验
-
/rpc-api/system/tenant/id-list
# 获得租户列表的时候,无需传递租户编号
-
/rpc-api/system/error-code/*
# 错误码的自动创建与下载的接口,无法带上租户编号
ignore-tables
:
-
system_tenant
...
...
归档/common/mall-spring-boot-starter-xxl-job/pom.xml
deleted
100644 → 0
浏览文件 @
4381d938
<?xml version="1.0" encoding="UTF-8"?>
<project
xmlns=
"http://maven.apache.org/POM/4.0.0"
xmlns:xsi=
"http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=
"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
>
<parent>
<artifactId>
common
</artifactId>
<groupId>
cn.iocoder.mall
</groupId>
<version>
1.0-SNAPSHOT
</version>
</parent>
<modelVersion>
4.0.0
</modelVersion>
<artifactId>
mall-spring-boot-starter-xxl-job
</artifactId>
<dependencies>
<!-- Spring 核心 -->
<dependency>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-configuration-processor
</artifactId>
<optional>
true
</optional>
</dependency>
<dependency>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-starter
</artifactId>
<optional>
true
</optional>
</dependency>
<!-- Job 相关 -->
<dependency>
<groupId>
com.xuxueli
</groupId>
<artifactId>
xxl-job-core
</artifactId>
</dependency>
</dependencies>
</project>
归档/common/mall-spring-boot-starter-xxl-job/src/main/resources/META-INF/spring.factories
deleted
100644 → 0
浏览文件 @
4381d938
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
cn.iocoder.mall.xxljob.config.XxlJobAutoConfiguration
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论