From f083bb2695f9cc0f2e898d92743aacc02a7c58e9 Mon Sep 17 00:00:00 2001 From: xuxueli <931591021@qq.com> Date: Wed, 11 Dec 2019 22:21:28 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B9=E6=B3=95=E4=BB=BB=E5=8A=A1=E6=94=AF?= =?UTF-8?q?=E6=8C=81=EF=BC=9A=E7=94=B1=E5=8E=9F=E6=9D=A5=E5=9F=BA=E4=BA=8E?= =?UTF-8?q?JobHandler=E7=B1=BB=E4=BB=BB=E5=8A=A1=E5=BC=80=E5=8F=91?= =?UTF-8?q?=E6=96=B9=E5=BC=8F=EF=BC=8C=E4=BC=98=E5=8C=96=E4=B8=BA=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E5=9F=BA=E4=BA=8E=E6=96=B9=E6=B3=95=E7=9A=84=E4=BB=BB?= =?UTF-8?q?=E5=8A=A1=E5=BC=80=E5=8F=91=E6=96=B9=E5=BC=8F=EF=BC=9B=E5=9B=A0?= =?UTF-8?q?=E6=AD=A4=EF=BC=8C=E5=8F=AF=E4=BB=A5=E6=94=AF=E6=8C=81=E5=8D=95?= =?UTF-8?q?=E4=B8=AA=E7=B1=BB=E4=B8=AD=E5=BC=80=E5=8F=91=E5=A4=9A=E4=B8=AA?= =?UTF-8?q?=E4=BB=BB=E5=8A=A1=E6=96=B9=E6=B3=95=EF=BC=8C=E8=BF=9B=E8=A1=8C?= =?UTF-8?q?=E7=B1=BB=E5=A4=8D=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/XXL-JOB官方文档.md | 17 +++-- .../executor/impl/XxlJobSpringExecutor.java | 58 +++++++++++++--- .../com/xxl/job/core/handler/IJobHandler.java | 6 +- .../core/handler/annotation/JobHandler.java | 15 ++-- .../job/core/handler/annotation/XxlJob.java | 30 ++++++++ .../job/core/handler/impl/GlueJobHandler.java | 1 + .../core/handler/impl/MethodJobHandler.java | 69 +++---------------- .../service/jobhandler/DemoJobHandler.java | 2 + .../service/jobhandler/SampleXxlJob.java | 44 ++++++++++++ 9 files changed, 159 insertions(+), 83 deletions(-) create mode 100644 xxl-job-core/src/main/java/com/xxl/job/core/handler/annotation/XxlJob.java create mode 100644 xxl-job-executor-samples/xxl-job-executor-sample-springboot/src/main/java/com/xxl/job/executor/service/jobhandler/SampleXxlJob.java diff --git a/doc/XXL-JOB官方文档.md b/doc/XXL-JOB官方文档.md index 2de8ed6f..d27d13f3 100644 --- a/doc/XXL-JOB官方文档.md +++ b/doc/XXL-JOB官方文档.md @@ -1630,10 +1630,19 @@ Tips: 历史版本(V1.3.x)目前已经Release至稳定版本, 进入维护阶段 - 25、项目依赖升级至较新稳定版本,如spring、spring-boot、mybatis、slf4j、groovy等等; ### 6.27 版本 v2.1.2 Release Notes[迭代中] -- 1、调度中心dispatcher servlet加载顺序优化; -- 2、执行器回调乱码问题修复; -- 3、[迭代中]移除commons-exec,采用原生方式实现; -- 4、[迭代中]任务操作API服务调整为restful方式,降低接入成本; +- 1、方法任务支持:由原来基于JobHandler类任务开发方式,优化为支持基于方法的任务开发方式;因此,可以支持单个类中开发多个任务方法,进行类复用(TODO:JobHandler移除); +``` +@XxlJob("demoJobHandler2") +public ReturnT execute(String param) { + XxlJobLogger.log("hello world"); + return ReturnT.SUCCESS; +} +``` +- 2、调度中心dispatcher servlet加载顺序优化; +- 3、执行器回调乱码问题修复; +- 4、[迭代中]移除commons-exec,采用原生方式实现; +- 5、[迭代中]任务操作API服务调整为restful方式,降低接入成本; + ### TODO LIST diff --git a/xxl-job-core/src/main/java/com/xxl/job/core/executor/impl/XxlJobSpringExecutor.java b/xxl-job-core/src/main/java/com/xxl/job/core/executor/impl/XxlJobSpringExecutor.java index 6f128a6a..afb192cf 100644 --- a/xxl-job-core/src/main/java/com/xxl/job/core/executor/impl/XxlJobSpringExecutor.java +++ b/xxl-job-core/src/main/java/com/xxl/job/core/executor/impl/XxlJobSpringExecutor.java @@ -1,9 +1,11 @@ package com.xxl.job.core.executor.impl; +import com.xxl.job.core.biz.model.ReturnT; import com.xxl.job.core.executor.XxlJobExecutor; import com.xxl.job.core.glue.GlueFactory; import com.xxl.job.core.handler.IJobHandler; import com.xxl.job.core.handler.annotation.JobHandler; +import com.xxl.job.core.handler.annotation.XxlJob; import com.xxl.job.core.handler.impl.MethodJobHandler; import org.springframework.beans.BeansException; import org.springframework.beans.factory.DisposableBean; @@ -29,11 +31,13 @@ public class XxlJobSpringExecutor extends XxlJobExecutor implements ApplicationC // init JobHandler Repository initJobHandlerRepository(applicationContext); + + // init JobHandler Repository (for method) initJobHandlerMethodRepository(applicationContext); + // refresh GlueFactory GlueFactory.refreshInstance(1); - // super start super.start(); } @@ -71,21 +75,59 @@ public class XxlJobSpringExecutor extends XxlJobExecutor implements ApplicationC if (applicationContext == null) { return; } + + // init job handler from method String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames(); for (String beanDefinitionName : beanDefinitionNames) { Object bean = applicationContext.getBean(beanDefinitionName); Method[] methods = bean.getClass().getDeclaredMethods(); - for (int i = 0; i < methods.length; i++) { - JobHandler jobHandler = AnnotationUtils.findAnnotation(methods[i], JobHandler.class); - if (jobHandler != null) { - String name = jobHandler.value(); - if (name.isEmpty()) { - name = methods[i].getName(); + for (Method method: methods) { + XxlJob xxlJob = AnnotationUtils.findAnnotation(method, XxlJob.class); + if (xxlJob != null) { + + // name + String name = xxlJob.value(); + if (name.trim().length() == 0) { + throw new RuntimeException("xxl-job method-jobhandler name invalid, for[" + bean.getClass() + "#"+ method.getName() +"] ."); } if (loadJobHandler(name) != null) { throw new RuntimeException("xxl-job jobhandler[" + name + "] naming conflicts."); } - registJobHandler(name, new MethodJobHandler(bean, methods[i], jobHandler)); + + // execute method + if (!(method.getParameterTypes()!=null && method.getParameterTypes().length==1 && method.getParameterTypes()[0].isAssignableFrom(String.class))) { + throw new RuntimeException("xxl-job method-jobhandler param-classtype invalid, for[" + bean.getClass() + "#"+ method.getName() +"] , " + + "The correct method format like \" public ReturnT execute(String param) \" ."); + } + if (!method.getReturnType().isAssignableFrom(ReturnT.class)) { + throw new RuntimeException("xxl-job method-jobhandler return-classtype invalid, for[" + bean.getClass() + "#"+ method.getName() +"] , " + + "The correct method format like \" public ReturnT execute(String param) \" ."); + } + method.setAccessible(true); + + // init and destory + Method initMethod = null; + Method destroyMethod = null; + + if(xxlJob.init().trim().length() > 0) { + try { + initMethod = bean.getClass().getDeclaredMethod(xxlJob.init()); + initMethod.setAccessible(true); + } catch (NoSuchMethodException e) { + throw new RuntimeException("xxl-job method-jobhandler initMethod invalid, for[" + bean.getClass() + "#"+ method.getName() +"] ."); + } + } + if(xxlJob.destroy().trim().length() > 0) { + try { + destroyMethod = bean.getClass().getDeclaredMethod(xxlJob.destroy()); + destroyMethod.setAccessible(true); + } catch (NoSuchMethodException e) { + throw new RuntimeException("xxl-job method-jobhandler destroyMethod invalid, for[" + bean.getClass() + "#"+ method.getName() +"] ."); + } + } + + // registry jobhandler + registJobHandler(name, new MethodJobHandler(bean, method, initMethod, destroyMethod)); } } } diff --git a/xxl-job-core/src/main/java/com/xxl/job/core/handler/IJobHandler.java b/xxl-job-core/src/main/java/com/xxl/job/core/handler/IJobHandler.java index e8e7dc2e..cc81d32d 100644 --- a/xxl-job-core/src/main/java/com/xxl/job/core/handler/IJobHandler.java +++ b/xxl-job-core/src/main/java/com/xxl/job/core/handler/IJobHandler.java @@ -2,6 +2,8 @@ package com.xxl.job.core.handler; import com.xxl.job.core.biz.model.ReturnT; +import java.lang.reflect.InvocationTargetException; + /** * job handler * @@ -31,7 +33,7 @@ public abstract class IJobHandler { /** * init handler, invoked when JobThread init */ - public void init() { + public void init() throws InvocationTargetException, IllegalAccessException { // do something } @@ -39,7 +41,7 @@ public abstract class IJobHandler { /** * destroy handler, invoked when JobThread destroy */ - public void destroy() { + public void destroy() throws InvocationTargetException, IllegalAccessException { // do something } diff --git a/xxl-job-core/src/main/java/com/xxl/job/core/handler/annotation/JobHandler.java b/xxl-job-core/src/main/java/com/xxl/job/core/handler/annotation/JobHandler.java index d6ba1e3e..a6ceb823 100644 --- a/xxl-job-core/src/main/java/com/xxl/job/core/handler/annotation/JobHandler.java +++ b/xxl-job-core/src/main/java/com/xxl/job/core/handler/annotation/JobHandler.java @@ -8,23 +8,16 @@ import java.lang.annotation.Target; /** * annotation for job handler + * + * * @author 2016-5-17 21:06:49 - * @author liuzh 2019-12-07 */ -@Target({ElementType.TYPE, ElementType.METHOD}) +@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Inherited +@Deprecated public @interface JobHandler { String value() default ""; - /** - * init handler, invoked when JobThread init - */ - String init() default ""; - - /** - * destroy handler, invoked when JobThread destroy - */ - String destroy() default ""; } diff --git a/xxl-job-core/src/main/java/com/xxl/job/core/handler/annotation/XxlJob.java b/xxl-job-core/src/main/java/com/xxl/job/core/handler/annotation/XxlJob.java new file mode 100644 index 00000000..b28eab5e --- /dev/null +++ b/xxl-job-core/src/main/java/com/xxl/job/core/handler/annotation/XxlJob.java @@ -0,0 +1,30 @@ +package com.xxl.job.core.handler.annotation; + +import java.lang.annotation.*; + +/** + * annotation for method jobhandler + * + * @author xuxueli 2019-12-11 20:50:13 + */ +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +public @interface XxlJob { + + /** + * jobhandler name + */ + String value() default ""; + + /** + * init handler, invoked when JobThread init + */ + String init() default ""; + + /** + * destroy handler, invoked when JobThread destroy + */ + String destroy() default ""; + +} diff --git a/xxl-job-core/src/main/java/com/xxl/job/core/handler/impl/GlueJobHandler.java b/xxl-job-core/src/main/java/com/xxl/job/core/handler/impl/GlueJobHandler.java index 3dc91a22..c1dadb22 100644 --- a/xxl-job-core/src/main/java/com/xxl/job/core/handler/impl/GlueJobHandler.java +++ b/xxl-job-core/src/main/java/com/xxl/job/core/handler/impl/GlueJobHandler.java @@ -6,6 +6,7 @@ import com.xxl.job.core.log.XxlJobLogger; /** * glue job handler + * * @author xuxueli 2016-5-19 21:05:45 */ public class GlueJobHandler extends IJobHandler { diff --git a/xxl-job-core/src/main/java/com/xxl/job/core/handler/impl/MethodJobHandler.java b/xxl-job-core/src/main/java/com/xxl/job/core/handler/impl/MethodJobHandler.java index b9753a79..620e47b4 100644 --- a/xxl-job-core/src/main/java/com/xxl/job/core/handler/impl/MethodJobHandler.java +++ b/xxl-job-core/src/main/java/com/xxl/job/core/handler/impl/MethodJobHandler.java @@ -2,52 +2,26 @@ package com.xxl.job.core.handler.impl; import com.xxl.job.core.biz.model.ReturnT; import com.xxl.job.core.handler.IJobHandler; -import com.xxl.job.core.handler.annotation.JobHandler; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; /** - * @author liuzh 2019-12-07 + * @author xuxueli 2019-12-11 21:12:18 */ public class MethodJobHandler extends IJobHandler { - private static Logger logger = LoggerFactory.getLogger(MethodJobHandler.class); private final Object target; private final Method method; - private final JobHandler jobHandler; private Method initMethod; private Method destroyMethod; - public MethodJobHandler(Object target, Method method, JobHandler jobHandler) { + public MethodJobHandler(Object target, Method method, Method initMethod, Method destroyMethod) { this.target = target; this.method = method; - this.jobHandler = jobHandler; - this.method.setAccessible(true); - this.prepareMethod(); - } - protected void prepareMethod() { - String init = jobHandler.init(); - if(!init.isEmpty()) { - try { - initMethod = target.getClass().getDeclaredMethod(init); - initMethod.setAccessible(true); - } catch (NoSuchMethodException e) { - logger.warn(e.getMessage(), e); - } - } - String destroy = jobHandler.destroy(); - if(!destroy.isEmpty()) { - try { - destroyMethod = target.getClass().getDeclaredMethod(destroy); - destroyMethod.setAccessible(true); - } catch (NoSuchMethodException e) { - logger.warn(e.getMessage(), e); - } - } + this.initMethod =initMethod; + this.destroyMethod =destroyMethod; } @Override @@ -56,42 +30,21 @@ public class MethodJobHandler extends IJobHandler { } @Override - public void init() { - super.init(); + public void init() throws InvocationTargetException, IllegalAccessException { if(initMethod != null) { - try { - initMethod.invoke(target); - } catch (IllegalAccessException e) { - logger.warn(e.getMessage(), e); - } catch (InvocationTargetException e) { - logger.warn(e.getMessage(), e); - } + initMethod.invoke(target); } } @Override - public void destroy() { - super.destroy(); + public void destroy() throws InvocationTargetException, IllegalAccessException { if(destroyMethod != null) { - try { - destroyMethod.invoke(target); - } catch (IllegalAccessException e) { - logger.warn(e.getMessage(), e); - } catch (InvocationTargetException e) { - logger.warn(e.getMessage(), e); - } + destroyMethod.invoke(target); } } - public Object getTarget() { - return target; - } - - public Method getMethod() { - return method; - } - - public JobHandler getJobHandler() { - return jobHandler; + @Override + public String toString() { + return super.toString()+"["+ target.getClass() + "#" + method.getName() +"]"; } } diff --git a/xxl-job-executor-samples/xxl-job-executor-sample-springboot/src/main/java/com/xxl/job/executor/service/jobhandler/DemoJobHandler.java b/xxl-job-executor-samples/xxl-job-executor-sample-springboot/src/main/java/com/xxl/job/executor/service/jobhandler/DemoJobHandler.java index 1768e48e..3a1e3a6f 100644 --- a/xxl-job-executor-samples/xxl-job-executor-sample-springboot/src/main/java/com/xxl/job/executor/service/jobhandler/DemoJobHandler.java +++ b/xxl-job-executor-samples/xxl-job-executor-sample-springboot/src/main/java/com/xxl/job/executor/service/jobhandler/DemoJobHandler.java @@ -10,6 +10,8 @@ import java.util.concurrent.TimeUnit; /** + * 【类方式任务开发即将废弃,建议采用方法方式开发,参考:com.xxl.job.executor.service.jobhandler.SampleXxlJob 】 + * * 任务Handler示例(Bean模式) * * 开发步骤: diff --git a/xxl-job-executor-samples/xxl-job-executor-sample-springboot/src/main/java/com/xxl/job/executor/service/jobhandler/SampleXxlJob.java b/xxl-job-executor-samples/xxl-job-executor-sample-springboot/src/main/java/com/xxl/job/executor/service/jobhandler/SampleXxlJob.java new file mode 100644 index 00000000..854866d1 --- /dev/null +++ b/xxl-job-executor-samples/xxl-job-executor-sample-springboot/src/main/java/com/xxl/job/executor/service/jobhandler/SampleXxlJob.java @@ -0,0 +1,44 @@ +package com.xxl.job.executor.service.jobhandler; + +import com.xxl.job.core.biz.model.ReturnT; +import com.xxl.job.core.handler.annotation.XxlJob; +import com.xxl.job.core.log.XxlJobLogger; +import org.springframework.stereotype.Component; + +/** + * XxlJob开发示例(Bean模式) + * + * 开发步骤: + * 1、在Spring Bean实例中,开发Job方法,方式格式要求为 "public ReturnT execute(String param)" + * 2、为Job方法添加注解 "@XxlJob(value="自定义jobhandler名称", init = "JobHandler初始化方法", destroy = "JobHandler销毁方法")",注解value值对应的是调度中心新建任务的JobHandler属性的值。 + * 3、执行日志:需要通过 "XxlJobLogger.log" 打印执行日志; + * + * @author xuxueli 2019-12-11 21:52:51 + */ +@Component +public class SampleXxlJob { + + + @XxlJob("demoJobHandler2") + public ReturnT execute(String param) { + + XxlJobLogger.log("222"); + return ReturnT.SUCCESS; + } + + @XxlJob(value="demoJobHandler3", init = "init", destroy = "destory") + public ReturnT execute3(String param) { + + XxlJobLogger.log("333"); + return ReturnT.SUCCESS; + } + + public void init(){ + System.out.println("init"); + } + + public void destory(){ + System.out.println("destory"); + } + +}