diff --git a/xxl-job/README.md b/xxl-job/README.md
new file mode 100644
index 000000000..5479731b0
--- /dev/null
+++ b/xxl-job/README.md
@@ -0,0 +1,25 @@
+# 依赖库名称
+简短地介绍本依赖库做了什么,包含了哪些逻辑。可以突出描述一下创新点。
+
+## 逻辑详情
+
+### 逻辑一
+
+描述逻辑的功能,逻辑的出入参。
+
+### 逻辑二
+
+描述逻辑的功能,逻辑的出入参。
+
+### 逻辑n...
+
+## 使用步骤说明
+
+1. 应用引用依赖库
+2. 配置应用配置参数(如果有的话)
+3. 逻辑调用示例截图
+4. ...
+
+## 应用演示链接
+
+[使用了本依赖库的制品应用链接]
diff --git a/xxl-job/pom.xml b/xxl-job/pom.xml
new file mode 100644
index 000000000..d315d23de
--- /dev/null
+++ b/xxl-job/pom.xml
@@ -0,0 +1,93 @@
+
+
+ 4.0.0
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.2.9.RELEASE
+
+
+
+ com.netease.lowcode
+ xxljob-tool
+ 2.0.0
+
+
+ 8
+ 8
+ UTF-8
+
+
+
+ nasl-metadata-collector
+ com.netease.lowcode
+ 0.12.0
+ true
+
+
+ com.xuxueli
+ xxl-job-core
+ 2.4.0
+
+
+ com.netease.lowcode
+ lcap-annotation
+ 1.0.6
+
+
+ org.apache.commons
+ commons-lang3
+ 3.9
+ provided
+
+
+ org.apache.commons
+ commons-collections4
+ 4.4
+ provided
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ ${jackson.version}
+
+
+ org.slf4j
+ slf4j-api
+ provided
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+ provided
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+
+
+ com.netease.lowcode
+ nasl-metadata-maven-plugin
+ 1.5.1
+
+ false
+ true
+
+
+
+
+ archive
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/xxl-job/src/main/java/com/netease/lowcode/xxljob/LibraryAutoScan.java b/xxl-job/src/main/java/com/netease/lowcode/xxljob/LibraryAutoScan.java
new file mode 100644
index 000000000..1dcd3917a
--- /dev/null
+++ b/xxl-job/src/main/java/com/netease/lowcode/xxljob/LibraryAutoScan.java
@@ -0,0 +1,8 @@
+package com.netease.lowcode.xxljob;
+
+/**
+ * 依赖库自动扫描类
+ * @author system
+ */
+public class LibraryAutoScan {
+}
diff --git a/xxl-job/src/main/java/com/netease/lowcode/xxljob/annotation/XxlJobLogicAnnotation.java b/xxl-job/src/main/java/com/netease/lowcode/xxljob/annotation/XxlJobLogicAnnotation.java
new file mode 100644
index 000000000..4bb14c4dc
--- /dev/null
+++ b/xxl-job/src/main/java/com/netease/lowcode/xxljob/annotation/XxlJobLogicAnnotation.java
@@ -0,0 +1,24 @@
+package com.netease.lowcode.xxljob.annotation;
+
+import com.netease.lowcode.annotation.LCAPLogicAnnotation;
+import com.netease.lowcode.core.annotation.NaslAnnotation;
+
+/**
+ * xxljob注解
+ *
+ * @author xujianping
+ */
+@NaslAnnotation(
+ applyTo = {NaslAnnotation.Component.LOGIC}
+)
+public class XxlJobLogicAnnotation extends LCAPLogicAnnotation {
+
+ @NaslAnnotation.Property(
+ title = "是否开启定时任务",
+ defaultValue = "false"
+ )
+ public Boolean useAnno;
+
+ @NaslAnnotation.Property(title = "JobHandler")
+ public String inputText;
+}
diff --git a/xxl-job/src/main/java/com/netease/lowcode/xxljob/annotation/XxlJobLogicAnnotationHandler.java b/xxl-job/src/main/java/com/netease/lowcode/xxljob/annotation/XxlJobLogicAnnotationHandler.java
new file mode 100644
index 000000000..1f219d712
--- /dev/null
+++ b/xxl-job/src/main/java/com/netease/lowcode/xxljob/annotation/XxlJobLogicAnnotationHandler.java
@@ -0,0 +1,36 @@
+package com.netease.lowcode.xxljob.annotation;
+
+import com.netease.lowcode.annotation.LCAPAnnotation;
+import com.netease.lowcode.annotation.context.LogicContext;
+import com.netease.lowcode.annotation.handler.LCAPAnnotationHandlerAdvise;
+import com.netease.lowcode.annotation.handler.LCAPLogicAnnotationHandler;
+
+import java.util.List;
+
+/**
+ * 防重放逻辑处理器
+ *
+ * @author xujianping
+ */
+public class XxlJobLogicAnnotationHandler implements LCAPLogicAnnotationHandler {
+
+ @Override
+ public LCAPAnnotationHandlerAdvise[] advises() {
+ return new LCAPAnnotationHandlerAdvise[]{LCAPAnnotationHandlerAdvise.BEFORE};
+ }
+
+ @Override
+ public Class extends LCAPAnnotation> consume() {
+ return XxlJobLogicAnnotation.class;
+ }
+
+ @Override
+ public Boolean report(List> logicContexts) {
+ return true;
+ }
+
+ @Override
+ public Object handle(Object[] args, Object result, LogicContext context) {
+ return null;
+ }
+}
diff --git a/xxl-job/src/main/java/com/netease/lowcode/xxljob/config/JobHandlerConfig.java b/xxl-job/src/main/java/com/netease/lowcode/xxljob/config/JobHandlerConfig.java
new file mode 100644
index 000000000..27631257e
--- /dev/null
+++ b/xxl-job/src/main/java/com/netease/lowcode/xxljob/config/JobHandlerConfig.java
@@ -0,0 +1,125 @@
+package com.netease.lowcode.xxljob.config;
+
+import com.netease.lowcode.annotation.context.LogicContext;
+import com.netease.lowcode.xxljob.config.helper.JobConfigHelper;
+import com.netease.lowcode.xxljob.model.JobHandlerInterfaceModel;
+import com.netease.lowcode.xxljob.task.InterfaceJobHandler;
+import com.xxl.job.core.executor.XxlJobExecutor;
+import com.xxl.job.core.executor.impl.XxlJobSpringExecutor;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.collections4.MapUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.boot.ApplicationArguments;
+import org.springframework.boot.ApplicationRunner;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.Resource;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+@Configuration
+public class JobHandlerConfig implements ApplicationRunner {
+
+ private static final Logger log = LoggerFactory.getLogger("LCAP_EXTENSION_LOGGER");
+
+ @Resource
+ private ApplicationContext applicationContext;
+ @Resource
+ private XxlJobConfig xxlJobConfig;
+
+ @Bean
+ public XxlJobSpringExecutor xxlJobExecutor() {
+ XxlJobSpringExecutor executor = new XxlJobSpringExecutor();
+ // 配置执行器参数
+ String adminAddress = xxlJobConfig.getAdminAddress();
+ if (StringUtils.isNotEmpty(adminAddress)) {
+ executor.setAdminAddresses(adminAddress.replace("\u200B", ""));
+ }
+ if (StringUtils.isNotEmpty(xxlJobConfig.getAppName())) {
+ executor.setAppname(xxlJobConfig.getAppName());
+ }
+ if (StringUtils.isNotEmpty(xxlJobConfig.getAddress())) {
+ executor.setAddress(xxlJobConfig.getAddress());
+ }
+ if (StringUtils.isNotEmpty(xxlJobConfig.getAccessToken())) {
+ executor.setAccessToken(xxlJobConfig.getAccessToken());
+ }
+ if (StringUtils.isNotEmpty(xxlJobConfig.getIp())) {
+ executor.setIp(xxlJobConfig.getIp());
+ }
+ if (StringUtils.isNotEmpty(xxlJobConfig.getLogPath())) {
+ executor.setLogPath(xxlJobConfig.getLogPath());
+ }
+ if (StringUtils.isNotEmpty(xxlJobConfig.getLogRetentionDays())) {
+ executor.setLogRetentionDays(Integer.parseInt(xxlJobConfig.getLogRetentionDays()));
+ }
+ if (StringUtils.isNotEmpty(xxlJobConfig.getPort())) {
+ executor.setPort(Integer.parseInt(xxlJobConfig.getPort()));
+ }
+ return executor;
+ }
+
+ /**
+ * 初始化并注册所有JobHandler
+ */
+// @PostConstruct
+ public void initJobHandlers() {
+ try {
+ // 获取xxlJob注解和logic的关系
+ List logicContexts = JobConfigHelper.listJobContext();
+ if (CollectionUtils.isEmpty(logicContexts)) {
+ return;
+ }
+
+ List jobModelList = logicContexts.stream()
+ .filter(e -> {
+ Map annotationProperties = e.getAnnotationProperties();
+ if (MapUtils.isEmpty(annotationProperties)) {
+ return false;
+ }
+
+ String useAnno = String.valueOf(annotationProperties.get("useAnno"));
+ String jobHandler = String.valueOf(annotationProperties.get("inputText"));
+ // 开启了开关,并设置了JobHandler才被判定开启了定时任务
+ if ("true".equals(useAnno) && StringUtils.isNotEmpty(jobHandler)) {
+ return true;
+ }
+ return false;
+ }).map(e -> {
+ Map annotationProperties = e.getAnnotationProperties();
+ JobHandlerInterfaceModel model = new JobHandlerInterfaceModel();
+ model.setJobHandler(String.valueOf(annotationProperties.get("inputText")));
+ model.setLogicName(e.getLogicName());
+ return model;
+ }).collect(Collectors.toList());
+
+ // 为每个配置创建JobHandler并注册
+ for (JobHandlerInterfaceModel config : jobModelList) {
+ String handlerName = config.getJobHandler();
+ // 创建处理器
+ InterfaceJobHandler handler = new InterfaceJobHandler(applicationContext, jobModelList) {
+ @Override
+ public String getHandlerName() {
+ return handlerName;
+ }
+ };
+
+ XxlJobSpringExecutor.registJobHandler(handlerName, handler);
+ log.info("Successfully registered job handler: {}", handlerName);
+ }
+ } catch (Exception e) {
+ log.error("Failed to initialize job handlers", e);
+ }
+ }
+
+ @Override
+ public void run(ApplicationArguments args) throws Exception {
+ initJobHandlers();
+ }
+}
\ No newline at end of file
diff --git a/xxl-job/src/main/java/com/netease/lowcode/xxljob/config/XxlJobConfig.java b/xxl-job/src/main/java/com/netease/lowcode/xxljob/config/XxlJobConfig.java
new file mode 100644
index 000000000..cf39d06cb
--- /dev/null
+++ b/xxl-job/src/main/java/com/netease/lowcode/xxljob/config/XxlJobConfig.java
@@ -0,0 +1,159 @@
+package com.netease.lowcode.xxljob.config;
+
+import com.netease.lowcode.core.EnvironmentType;
+import com.netease.lowcode.core.annotation.Environment;
+import com.netease.lowcode.core.annotation.NaslConfiguration;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class XxlJobConfig {
+
+ /**
+ * xxlJob地址
+ */
+ @Value("${adminAddress:}")
+ @NaslConfiguration(defaultValue = {
+ @Environment(type = EnvironmentType.DEV, value = ""),
+ @Environment(type = EnvironmentType.ONLINE, value = "")
+ })
+ public String adminAddress;
+
+ /**
+ * 应用名称
+ */
+ @Value("${appName:}")
+ @NaslConfiguration(defaultValue = {
+ @Environment(type = EnvironmentType.DEV, value = ""),
+ @Environment(type = EnvironmentType.ONLINE, value = "")
+ })
+ public String appName;
+
+ /**
+ * token
+ */
+ @Value("${accessToken:}")
+ @NaslConfiguration(defaultValue = {
+ @Environment(type = EnvironmentType.DEV, value = ""),
+ @Environment(type = EnvironmentType.ONLINE, value = "")
+ })
+ public String accessToken;
+
+ /**
+ * 执行器注册地址
+ */
+ @Value("${address:}")
+ @NaslConfiguration(defaultValue = {
+ @Environment(type = EnvironmentType.DEV, value = ""),
+ @Environment(type = EnvironmentType.ONLINE, value = "")
+ })
+ public String address;
+
+ /**
+ * ip
+ */
+ @Value("${ip:}")
+ @NaslConfiguration(defaultValue = {
+ @Environment(type = EnvironmentType.DEV, value = ""),
+ @Environment(type = EnvironmentType.ONLINE, value = "")
+ })
+ public String ip;
+
+ /**
+ * 端口
+ */
+ @Value("${port:}")
+ @NaslConfiguration(defaultValue = {
+ @Environment(type = EnvironmentType.DEV, value = ""),
+ @Environment(type = EnvironmentType.ONLINE, value = "")
+ })
+ public String port;
+
+
+ /**
+ * 日志地址
+ */
+ @Value("${logPath:logs/xxl-job/jobHandler}")
+ @NaslConfiguration(defaultValue = {
+ @Environment(type = EnvironmentType.DEV, value = "logs/xxl-job/jobHandler"),
+ @Environment(type = EnvironmentType.ONLINE, value = "logs/xxl-job/jobHandler")
+ })
+ public String logPath;
+
+ /**
+ * 日志过期时间
+ */
+ @Value("${logRetentionDays:30}")
+ @NaslConfiguration(defaultValue = {
+ @Environment(type = EnvironmentType.DEV, value = "30"),
+ @Environment(type = EnvironmentType.ONLINE, value = "30")
+ })
+ public String logRetentionDays;
+
+ public String getPort() {
+ return port;
+ }
+
+ public void setPort(String port) {
+ this.port = port;
+ }
+
+ public void setLogRetentionDays(String logRetentionDays) {
+ this.logRetentionDays = logRetentionDays;
+ }
+
+ public String getAdminAddress() {
+ return this.adminAddress;
+ }
+
+ public void setAdminAddress(String adminAddress) {
+ this.adminAddress = adminAddress;
+ }
+
+
+
+ public String getAppName() {
+ return this.appName;
+ }
+
+ public void setAppName(String appName) {
+ this.appName = appName;
+ }
+
+ public String getAccessToken() {
+ return this.accessToken;
+ }
+
+ public void setAccessToken(String accessToken) {
+ this.accessToken = accessToken;
+ }
+
+ public String getIp() {
+ return this.ip;
+ }
+
+ public void setIp(String ip) {
+ this.ip = ip;
+ }
+
+
+ public String getLogPath() {
+ return this.logPath;
+ }
+
+ public void setLogPath(String logPath) {
+ this.logPath = logPath;
+ }
+
+ public String getLogRetentionDays() {
+ return logRetentionDays;
+ }
+
+ public String getAddress() {
+ return address;
+ }
+
+ public void setAddress(String address) {
+ this.address = address;
+ }
+}
diff --git a/xxl-job/src/main/java/com/netease/lowcode/xxljob/config/helper/JobConfigHelper.java b/xxl-job/src/main/java/com/netease/lowcode/xxljob/config/helper/JobConfigHelper.java
new file mode 100644
index 000000000..3483aebdd
--- /dev/null
+++ b/xxl-job/src/main/java/com/netease/lowcode/xxljob/config/helper/JobConfigHelper.java
@@ -0,0 +1,53 @@
+package com.netease.lowcode.xxljob.config.helper;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.netease.lowcode.annotation.context.LogicContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.core.io.ClassPathResource;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.List;
+
+/**
+ * job配置帮助类
+ */
+public class JobConfigHelper {
+
+ private static final Logger log = LoggerFactory.getLogger("LCAP_EXTENSION_LOGGER");
+
+ public static List listJobContext() {
+ String filePath = "annotation/annotation_metadata_logic_XxlJobLogicAnnotation.json";
+ return readFileToCollect(filePath, new TypeReference>() {
+ });
+ }
+
+ /**
+ * 从主程序源json文件中读取配置数据
+ */
+ private static T readFileToCollect(String filePath, TypeReference typeReference) {
+ ObjectMapper objectMapper = new ObjectMapper();
+ ClassPathResource classPathResource = new ClassPathResource(filePath);
+ InputStream inputStream = null;
+ try {
+ inputStream = classPathResource.getInputStream();
+ } catch (FileNotFoundException fnfe) {
+ log.info("library file [{}] not exist", filePath);
+ return null;
+ } catch (IOException e) {
+ log.error("library fail to read file [{}]", filePath, e);
+ return null;
+ }
+ T readValue = null;
+ try {
+ readValue = objectMapper.readValue(inputStream, typeReference);
+ } catch (IOException e) {
+ log.error("library fail to deserialize file content [{}]", filePath, e);
+ return null;
+ }
+ return readValue;
+ }
+}
diff --git a/xxl-job/src/main/java/com/netease/lowcode/xxljob/model/JobHandlerInterfaceModel.java b/xxl-job/src/main/java/com/netease/lowcode/xxljob/model/JobHandlerInterfaceModel.java
new file mode 100644
index 000000000..e1b4bcf81
--- /dev/null
+++ b/xxl-job/src/main/java/com/netease/lowcode/xxljob/model/JobHandlerInterfaceModel.java
@@ -0,0 +1,22 @@
+package com.netease.lowcode.xxljob.model;
+
+public class JobHandlerInterfaceModel {
+ private String logicName; // 接口名称
+ private String jobHandler; // xxlJob handler
+
+ public String getLogicName() {
+ return logicName;
+ }
+
+ public void setLogicName(String logicName) {
+ this.logicName = logicName;
+ }
+
+ public String getJobHandler() {
+ return jobHandler;
+ }
+
+ public void setJobHandler(String jobHandler) {
+ this.jobHandler = jobHandler;
+ }
+}
diff --git a/xxl-job/src/main/java/com/netease/lowcode/xxljob/spring/XxlJobSpringEnvironmentConfiguration.java b/xxl-job/src/main/java/com/netease/lowcode/xxljob/spring/XxlJobSpringEnvironmentConfiguration.java
new file mode 100644
index 000000000..fe923c36d
--- /dev/null
+++ b/xxl-job/src/main/java/com/netease/lowcode/xxljob/spring/XxlJobSpringEnvironmentConfiguration.java
@@ -0,0 +1,13 @@
+package com.netease.lowcode.xxljob.spring;
+
+import com.netease.lowcode.xxljob.LibraryAutoScan;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * 加入spring环境配置(在spring.factories中指定)
+ */
+@Configuration
+@ComponentScan(basePackageClasses = LibraryAutoScan.class)
+public class XxlJobSpringEnvironmentConfiguration {
+}
diff --git a/xxl-job/src/main/java/com/netease/lowcode/xxljob/task/InterfaceJobHandler.java b/xxl-job/src/main/java/com/netease/lowcode/xxljob/task/InterfaceJobHandler.java
new file mode 100644
index 000000000..d998fc2ff
--- /dev/null
+++ b/xxl-job/src/main/java/com/netease/lowcode/xxljob/task/InterfaceJobHandler.java
@@ -0,0 +1,82 @@
+package com.netease.lowcode.xxljob.task;
+
+import com.netease.lowcode.xxljob.model.JobHandlerInterfaceModel;
+import com.netease.lowcode.xxljob.util.SpringContextUtil;
+import com.xxl.job.core.context.XxlJobHelper;
+import com.xxl.job.core.handler.IJobHandler;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.aop.support.AopUtils;
+import org.springframework.context.ApplicationContext;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * 基于接口的JobHandler基类
+ */
+public abstract class InterfaceJobHandler extends IJobHandler {
+
+ private static final Logger log = LoggerFactory.getLogger("LCAP_EXTENSION_LOGGER");
+
+ protected final ApplicationContext applicationContext;
+ private List jobModelList;
+
+ public InterfaceJobHandler(ApplicationContext applicationContext, List jobModelList) {
+ this.applicationContext = applicationContext;
+ this.jobModelList = jobModelList;
+ }
+
+ /**
+ * 获取处理器名称
+ */
+ public abstract String getHandlerName();
+
+ @Override
+ public void execute() {
+ String threadName = Thread.currentThread().getName();
+ threadName = threadName.replace(",", "").replace(" ", "");
+ Thread.currentThread().setName(threadName);
+ String param = XxlJobHelper.getJobParam();
+ String handlerName = getHandlerName();
+ XxlJobHelper.log("任务开始执行,handler=" + getHandlerName() + ", 参数=" + param);
+ log.info("xxl job execute = {}", handlerName);
+ List modelList = jobModelList.stream()
+ .filter(e -> e.getJobHandler().equals(handlerName))
+ .collect(Collectors.toList());
+ // 一个job handler可能在多个接口上
+ for (JobHandlerInterfaceModel model : modelList) {
+ Object bean = SpringContextUtil.getCustomServiceBean(model.getLogicName());
+ if (bean == null) {
+ log.error("Failed to get bean: {}", model.getLogicName());
+ XxlJobHelper.log("获取bean失败: " + model.getLogicName());
+ XxlJobHelper.handleFail("获取bean失败: " + model.getLogicName());
+ return;
+ }
+ Class> aClass = AopUtils.getTargetClass(bean);
+ try {
+ // 无参
+ Method targetMethod = aClass.getDeclaredMethod(model.getLogicName());
+ targetMethod.invoke(bean);
+ } catch (NoSuchMethodException exception) {
+ try {
+ Method targetMethod = aClass.getDeclaredMethod(model.getLogicName(), String.class);
+ targetMethod.invoke(bean, param);
+ } catch (Exception e) {
+ log.error("Execute job failed: " + handlerName, ((InvocationTargetException) e).getTargetException().getMessage());
+ XxlJobHelper.log("任务执行失败: " + ((InvocationTargetException) e).getTargetException().getMessage());
+ XxlJobHelper.handleFail("任务执行失败: " + ((InvocationTargetException) e).getTargetException().getMessage());
+ return;
+ }
+ } catch (Exception e) {
+ log.error("Execute job failed: " + handlerName, e);
+ XxlJobHelper.log("任务执行失败: " + ((InvocationTargetException) e).getTargetException().getMessage());
+ XxlJobHelper.handleFail("任务执行失败: " + ((InvocationTargetException) e).getTargetException().getMessage());
+ return;
+ }
+ }
+ XxlJobHelper.handleSuccess("任务执行成功");
+ }
+}
\ No newline at end of file
diff --git a/xxl-job/src/main/java/com/netease/lowcode/xxljob/util/SpringContextUtil.java b/xxl-job/src/main/java/com/netease/lowcode/xxljob/util/SpringContextUtil.java
new file mode 100644
index 000000000..e1ebeb14d
--- /dev/null
+++ b/xxl-job/src/main/java/com/netease/lowcode/xxljob/util/SpringContextUtil.java
@@ -0,0 +1,118 @@
+package com.netease.lowcode.xxljob.util;
+
+import org.springframework.beans.BeansException;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.stereotype.Component;
+import org.springframework.stereotype.Service;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * spring上下文工具类
+ *
+ * @author xujianping
+ */
+@Component("xxlJobLibrarySpringContextUtil")
+public class SpringContextUtil implements ApplicationContextAware {
+
+ private static final String SUFFIX_BEAN_NAME = "CustomizeService";
+ private static final String SUFFIX_BEAN_NAME_4X = "LogicService";
+ private static final String SUFFIX_BEAN_NAME_4X_OVERRIDDEN = "OverriddenLogicLibService";
+ private static final List SUFFIX_BEAN_NAME_4X_LIST = Arrays.asList("LogicService"
+ , "LogicLibService"
+ , "OverriddenLogicLibService"
+ , "AuthroizationService"
+ , "AuthorizationConnectorService"
+ , "AuthenticationService"
+ , "AuthenticationConnectorService"
+ , "EntityService"
+ , "ConnectorService"
+ , "ProcessService"
+ , "DownloadFileService");
+ private static ApplicationContext applicationContext;
+
+ /**
+ * 获取applicationContext
+ */
+ public static ApplicationContext getApplicationContext() {
+ return applicationContext;
+ }
+
+ @Override
+ public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+ SpringContextUtil.applicationContext = applicationContext;
+ }
+
+ /**
+ * 通过namePrex获取custom service Bean.
+ */
+ public static Object getCustomServiceBean(String namePrex) {
+ // 获取所有@Service注解的Bean
+ Map serviceBeans = getApplicationContext().getBeansWithAnnotation(Service.class);
+ if (serviceBeans.isEmpty()) {
+ return null;
+ }
+ Map targetServiceBeans = serviceBeans.entrySet().stream()
+ .filter(entry -> entry.getKey().startsWith(namePrex))
+ .filter(entry -> {
+ String endStr = entry.getKey().replace(namePrex, "");
+ return SUFFIX_BEAN_NAME.equals(endStr) || SUFFIX_BEAN_NAME_4X.equals(endStr);
+ })
+ .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
+ return !targetServiceBeans.isEmpty() ? targetServiceBeans.values().iterator().next() : null;
+ }
+
+ /**
+ * 通过namePrex获取custom service Bean.
+ */
+ public static Object getCommonServiceBean(String namePrex) {
+ // 获取所有@Service注解的Bean
+ Map serviceBeans = getApplicationContext().getBeansWithAnnotation(Service.class);
+ if (serviceBeans.isEmpty()) {
+ return null;
+ }
+ Map targetServiceBeans = serviceBeans.entrySet().stream()
+ .filter(entry -> entry.getKey().startsWith(namePrex))
+ .filter(entry -> {
+ String endStr = entry.getKey().replace(namePrex, "");
+ if (SUFFIX_BEAN_NAME.equals(endStr)) {
+ return true;
+ }
+ return SUFFIX_BEAN_NAME_4X_LIST.stream()
+ .anyMatch(suffix -> suffix.equals(endStr));
+ })
+ .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
+ return !targetServiceBeans.isEmpty() ? targetServiceBeans.values().iterator().next() : null;
+ }
+
+ /**
+ * 通过namePrex获取custom service Bean.
+ */
+ public static Object getCustomOverriddenServiceBean(String namePrex) {
+ // 获取所有@Service注解的Bean
+ Map serviceBeans = getApplicationContext().getBeansWithAnnotation(Service.class);
+ if (serviceBeans.isEmpty()) {
+ return null;
+ }
+ Map targetServiceBeans = serviceBeans.entrySet().stream()
+ .filter(entry -> entry.getKey().startsWith(namePrex))
+ .filter(entry -> {
+ String endStr = entry.getKey().replace(namePrex, "");
+ return SUFFIX_BEAN_NAME_4X_OVERRIDDEN.equals(endStr);
+ })
+ .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
+ return !targetServiceBeans.isEmpty() ? targetServiceBeans.values().iterator().next() : null;
+ }
+
+ /**
+ * 通过name获取Bean.
+ */
+ public static Object getBean(String name) {
+ return getApplicationContext().getBean(name);
+ }
+
+}
\ No newline at end of file
diff --git a/xxl-job/src/main/resources/META-INF/spring.factories b/xxl-job/src/main/resources/META-INF/spring.factories
new file mode 100644
index 000000000..bf0c6f4b4
--- /dev/null
+++ b/xxl-job/src/main/resources/META-INF/spring.factories
@@ -0,0 +1,2 @@
+org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
+com.netease.lowcode.xxljob.spring.XxlJobSpringEnvironmentConfiguration
\ No newline at end of file