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 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