From b9bd8079f29dcf894f96efcf09c14fcc2e830cd1 Mon Sep 17 00:00:00 2001 From: wangxiaopeng <157894372@qq.com> Date: Thu, 6 Apr 2023 18:08:56 +0800 Subject: [PATCH] =?UTF-8?q?=E8=B0=83=E5=BA=A6=E6=96=B9=E5=BC=8F=EF=BC=88?= =?UTF-8?q?=E6=96=B9=E6=B3=95=E5=BD=A2=E5=BC=8F=EF=BC=89=E6=96=B0=E5=A2=9E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tester/SpringMethodProcessorService.java | 17 ++ .../powerjob/worker/PowerJobSpringWorker.java | 3 + .../powerjob/worker/annotation/PowerJob.java | 22 +++ .../processor/MethodBasicProcessor.java | 25 +++ .../BuildInSpringMethodProcessorFactory.java | 146 ++++++++++++++++++ .../impl/BuiltInSpringProcessorFactory.java | 8 +- 6 files changed, 219 insertions(+), 2 deletions(-) create mode 100644 powerjob-worker-samples/src/main/java/tech/powerjob/samples/tester/SpringMethodProcessorService.java create mode 100644 powerjob-worker/src/main/java/tech/powerjob/worker/annotation/PowerJob.java create mode 100644 powerjob-worker/src/main/java/tech/powerjob/worker/processor/MethodBasicProcessor.java create mode 100644 powerjob-worker/src/main/java/tech/powerjob/worker/processor/impl/BuildInSpringMethodProcessorFactory.java diff --git a/powerjob-worker-samples/src/main/java/tech/powerjob/samples/tester/SpringMethodProcessorService.java b/powerjob-worker-samples/src/main/java/tech/powerjob/samples/tester/SpringMethodProcessorService.java new file mode 100644 index 00000000..62138555 --- /dev/null +++ b/powerjob-worker-samples/src/main/java/tech/powerjob/samples/tester/SpringMethodProcessorService.java @@ -0,0 +1,17 @@ +package tech.powerjob.samples.tester; + +import org.springframework.stereotype.Component; +import tech.powerjob.worker.annotation.PowerJob; +import tech.powerjob.worker.core.processor.TaskContext; +import tech.powerjob.worker.log.OmsLogger; + +@Component +public class SpringMethodProcessorService { + + @PowerJob("test") + public void test(TaskContext context) { + OmsLogger omsLogger = context.getOmsLogger(); + omsLogger.warn("测试日志"); + System.out.println("测试执行"); + } +} diff --git a/powerjob-worker/src/main/java/tech/powerjob/worker/PowerJobSpringWorker.java b/powerjob-worker/src/main/java/tech/powerjob/worker/PowerJobSpringWorker.java index 0bc21136..d6fb62f6 100644 --- a/powerjob-worker/src/main/java/tech/powerjob/worker/PowerJobSpringWorker.java +++ b/powerjob-worker/src/main/java/tech/powerjob/worker/PowerJobSpringWorker.java @@ -8,6 +8,7 @@ import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import tech.powerjob.worker.common.PowerJobWorkerConfig; import tech.powerjob.worker.extension.processor.ProcessorFactory; +import tech.powerjob.worker.processor.impl.BuildInSpringMethodProcessorFactory; import tech.powerjob.worker.processor.impl.BuiltInSpringProcessorFactory; import java.util.Collections; @@ -43,12 +44,14 @@ public class PowerJobSpringWorker implements ApplicationContextAware, Initializi public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { BuiltInSpringProcessorFactory springProcessorFactory = new BuiltInSpringProcessorFactory(applicationContext); + BuildInSpringMethodProcessorFactory springMethodProcessorFactory = new BuildInSpringMethodProcessorFactory(applicationContext); // append BuiltInSpringProcessorFactory List processorFactories = Lists.newArrayList( Optional.ofNullable(config.getProcessorFactoryList()) .orElse(Collections.emptyList())); processorFactories.add(springProcessorFactory); + processorFactories.add(springMethodProcessorFactory); config.setProcessorFactoryList(processorFactories); } diff --git a/powerjob-worker/src/main/java/tech/powerjob/worker/annotation/PowerJob.java b/powerjob-worker/src/main/java/tech/powerjob/worker/annotation/PowerJob.java new file mode 100644 index 00000000..07c5fec0 --- /dev/null +++ b/powerjob-worker/src/main/java/tech/powerjob/worker/annotation/PowerJob.java @@ -0,0 +1,22 @@ +package tech.powerjob.worker.annotation; + + +import java.lang.annotation.*; + +/** + * 方法级别的power-job调度 + */ +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +public @interface PowerJob { + + + /** + * handler name + */ + String value(); + + + +} diff --git a/powerjob-worker/src/main/java/tech/powerjob/worker/processor/MethodBasicProcessor.java b/powerjob-worker/src/main/java/tech/powerjob/worker/processor/MethodBasicProcessor.java new file mode 100644 index 00000000..84425ecc --- /dev/null +++ b/powerjob-worker/src/main/java/tech/powerjob/worker/processor/MethodBasicProcessor.java @@ -0,0 +1,25 @@ +package tech.powerjob.worker.processor; + +import tech.powerjob.worker.core.processor.ProcessResult; +import tech.powerjob.worker.core.processor.TaskContext; +import tech.powerjob.worker.core.processor.sdk.BasicProcessor; + +import java.lang.reflect.Method; + +public class MethodBasicProcessor implements BasicProcessor { + + private final Object bean; + + private final Method method; + + public MethodBasicProcessor(Object bean, Method method) { + this.bean = bean; + this.method = method; + } + + @Override + public ProcessResult process(TaskContext context) throws Exception { + method.invoke(bean,context); + return new ProcessResult(true); + } +} diff --git a/powerjob-worker/src/main/java/tech/powerjob/worker/processor/impl/BuildInSpringMethodProcessorFactory.java b/powerjob-worker/src/main/java/tech/powerjob/worker/processor/impl/BuildInSpringMethodProcessorFactory.java new file mode 100644 index 00000000..de29b1ed --- /dev/null +++ b/powerjob-worker/src/main/java/tech/powerjob/worker/processor/impl/BuildInSpringMethodProcessorFactory.java @@ -0,0 +1,146 @@ +package tech.powerjob.worker.processor.impl; + +import com.google.common.collect.Sets; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.context.ApplicationContext; +import tech.powerjob.common.enums.ProcessorType; +import tech.powerjob.worker.annotation.PowerJob; +import tech.powerjob.worker.extension.processor.ProcessorBean; +import tech.powerjob.worker.extension.processor.ProcessorDefinition; +import tech.powerjob.worker.extension.processor.ProcessorFactory; +import tech.powerjob.worker.processor.MethodBasicProcessor; + +import java.lang.reflect.Method; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +/** + * 内建的 SpringBean 处理器工厂,用于加载 Spring 管理Bean下的方法(使用PowerJob注解),非核心依赖 + * + * @author wxp + * @since 2023/4/06 + */ + +@Slf4j +public class BuildInSpringMethodProcessorFactory implements ProcessorFactory { + + private final ApplicationContext applicationContext; + + private static final List jobHandlerRepository = new LinkedList<>(); + + private final static String DELIMITER = "#"; + + + public BuildInSpringMethodProcessorFactory(ApplicationContext applicationContext) { + this.applicationContext = applicationContext; + } + + + @Override + public Set supportTypes() { + return Sets.newHashSet(ProcessorType.BUILT_IN.name()); + } + + @Override + public ProcessorBean build(ProcessorDefinition processorDefinition) { + try { + boolean canLoad = checkCanLoad(); + if (!canLoad) { + log.info("[ProcessorFactory] can't find Spring env, this processor can't load by 'BuildInSpringMethodProcessorFactory'"); + return null; + } + String processorInfo = processorDefinition.getProcessorInfo(); + if (!processorInfo.contains(DELIMITER)) { + log.info("[ProcessorFactory] can't parse processorDefinition, this processor can't load by 'BuildInSpringMethodProcessorFactory'"); + return null; + } + String[] split = processorInfo.split("#"); + String methodName = split[1]; + String className = split[0]; + Object bean = getBean(className,applicationContext); + Method[] methods = bean.getClass().getDeclaredMethods(); + for (Method method : methods) { + PowerJob powerJob = method.getAnnotation(PowerJob.class); + if (powerJob == null) { + continue; + } + String name = powerJob.value(); + //匹配到和页面定义相同的methodName + if (!name.equals(methodName)) { + continue; + } + if (name.trim().length() == 0) { + throw new RuntimeException("method-jobhandler name invalid, for[" + bean.getClass() + "#" + method.getName() + "] ."); + } + if (containsJobHandler(name)) { + throw new RuntimeException("jobhandler[" + name + "] naming conflicts."); + } + method.setAccessible(true); + registerJobHandler(methodName); + + MethodBasicProcessor processor = new MethodBasicProcessor(bean, method); + return new ProcessorBean() + .setProcessor(processor) + .setClassLoader(processor.getClass().getClassLoader()); + } + } catch (NoSuchBeanDefinitionException ignore) { + log.warn("[ProcessorFactory] can't find the processor in SPRING"); + } catch (Throwable t) { + log.warn("[ProcessorFactory] load by BuiltInSpringProcessorFactory failed. If you are using Spring, make sure this bean was managed by Spring", t); + } + return null; + + } + + + public static void registerJobHandler(String name) { + jobHandlerRepository.add(name); + } + + + private boolean containsJobHandler(String name) { + return jobHandlerRepository.contains(name); + } + + private boolean checkCanLoad() { + try { + ApplicationContext.class.getClassLoader(); + return applicationContext != null; + } catch (Throwable ignore) { + } + return false; + } + + + @SuppressWarnings("unchecked") + private static Object getBean(String className, ApplicationContext ctx) throws Exception { + + // 0. 尝试直接用 Bean 名称加载 + try { + final Object bean = ctx.getBean(className); + if (bean != null) { + return bean; + } + } catch (Exception ignore) { + } + + // 1. ClassLoader 存在,则直接使用 clz 加载 + ClassLoader classLoader = ctx.getClassLoader(); + if (classLoader != null) { + return ctx.getBean(classLoader.loadClass(className)); + } + // 2. ClassLoader 不存在(系统类加载器不可见),尝试用类名称小写加载 + String[] split = className.split("\\."); + String beanName = split[split.length - 1]; + // 小写转大写 + char[] cs = beanName.toCharArray(); + cs[0] += 32; + String beanName0 = String.valueOf(cs); + log.warn("[SpringUtils] can't get ClassLoader from context[{}], try to load by beanName:{}", ctx, beanName0); + return ctx.getBean(beanName0); + } + + +} diff --git a/powerjob-worker/src/main/java/tech/powerjob/worker/processor/impl/BuiltInSpringProcessorFactory.java b/powerjob-worker/src/main/java/tech/powerjob/worker/processor/impl/BuiltInSpringProcessorFactory.java index 3ce7481f..6408a6f7 100644 --- a/powerjob-worker/src/main/java/tech/powerjob/worker/processor/impl/BuiltInSpringProcessorFactory.java +++ b/powerjob-worker/src/main/java/tech/powerjob/worker/processor/impl/BuiltInSpringProcessorFactory.java @@ -41,8 +41,12 @@ public class BuiltInSpringProcessorFactory implements ProcessorFactory { log.info("[ProcessorFactory] can't find Spring env, this processor can't load by 'BuiltInSpringProcessorFactory'"); return null; } - - BasicProcessor basicProcessor = getBean(processorDefinition.getProcessorInfo(), applicationContext); + String processorInfo = processorDefinition.getProcessorInfo(); + //用于区分方法级别的参数 + if (processorInfo.contains("#")) { + return null; + } + BasicProcessor basicProcessor = getBean(processorInfo, applicationContext); return new ProcessorBean() .setProcessor(basicProcessor) .setClassLoader(basicProcessor.getClass().getClassLoader());