方法任务支持:由原来基于JobHandler类任务开发方式,优化为支持基于方法的任务开发方式;因此,可以支持单个类中开发多个任务方法,进行类复用

This commit is contained in:
xuxueli 2019-12-11 22:21:28 +08:00
parent 49f7e16954
commit f083bb2695
9 changed files with 159 additions and 83 deletions

View File

@ -1630,10 +1630,19 @@ Tips: 历史版本(V1.3.x)目前已经Release至稳定版本, 进入维护阶段
- 25、项目依赖升级至较新稳定版本如spring、spring-boot、mybatis、slf4j、groovy等等 - 25、项目依赖升级至较新稳定版本如spring、spring-boot、mybatis、slf4j、groovy等等
### 6.27 版本 v2.1.2 Release Notes[迭代中] ### 6.27 版本 v2.1.2 Release Notes[迭代中]
- 1、调度中心dispatcher servlet加载顺序优化 - 1、方法任务支持由原来基于JobHandler类任务开发方式优化为支持基于方法的任务开发方式因此可以支持单个类中开发多个任务方法进行类复用TODOJobHandler移除
- 2、执行器回调乱码问题修复 ```
- 3、[迭代中]移除commons-exec采用原生方式实现 @XxlJob("demoJobHandler2")
- 4、[迭代中]任务操作API服务调整为restful方式降低接入成本 public ReturnT<String> execute(String param) {
XxlJobLogger.log("hello world");
return ReturnT.SUCCESS;
}
```
- 2、调度中心dispatcher servlet加载顺序优化
- 3、执行器回调乱码问题修复
- 4、[迭代中]移除commons-exec采用原生方式实现
- 5、[迭代中]任务操作API服务调整为restful方式降低接入成本
### TODO LIST ### TODO LIST

View File

@ -1,9 +1,11 @@
package com.xxl.job.core.executor.impl; 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.executor.XxlJobExecutor;
import com.xxl.job.core.glue.GlueFactory; import com.xxl.job.core.glue.GlueFactory;
import com.xxl.job.core.handler.IJobHandler; import com.xxl.job.core.handler.IJobHandler;
import com.xxl.job.core.handler.annotation.JobHandler; 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 com.xxl.job.core.handler.impl.MethodJobHandler;
import org.springframework.beans.BeansException; import org.springframework.beans.BeansException;
import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.DisposableBean;
@ -29,11 +31,13 @@ public class XxlJobSpringExecutor extends XxlJobExecutor implements ApplicationC
// init JobHandler Repository // init JobHandler Repository
initJobHandlerRepository(applicationContext); initJobHandlerRepository(applicationContext);
// init JobHandler Repository (for method)
initJobHandlerMethodRepository(applicationContext); initJobHandlerMethodRepository(applicationContext);
// refresh GlueFactory // refresh GlueFactory
GlueFactory.refreshInstance(1); GlueFactory.refreshInstance(1);
// super start // super start
super.start(); super.start();
} }
@ -71,21 +75,59 @@ public class XxlJobSpringExecutor extends XxlJobExecutor implements ApplicationC
if (applicationContext == null) { if (applicationContext == null) {
return; return;
} }
// init job handler from method
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames(); String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) { for (String beanDefinitionName : beanDefinitionNames) {
Object bean = applicationContext.getBean(beanDefinitionName); Object bean = applicationContext.getBean(beanDefinitionName);
Method[] methods = bean.getClass().getDeclaredMethods(); Method[] methods = bean.getClass().getDeclaredMethods();
for (int i = 0; i < methods.length; i++) { for (Method method: methods) {
JobHandler jobHandler = AnnotationUtils.findAnnotation(methods[i], JobHandler.class); XxlJob xxlJob = AnnotationUtils.findAnnotation(method, XxlJob.class);
if (jobHandler != null) { if (xxlJob != null) {
String name = jobHandler.value();
if (name.isEmpty()) { // name
name = methods[i].getName(); 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) { if (loadJobHandler(name) != null) {
throw new RuntimeException("xxl-job jobhandler[" + name + "] naming conflicts."); 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<String> 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<String> 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));
} }
} }
} }

View File

@ -2,6 +2,8 @@ package com.xxl.job.core.handler;
import com.xxl.job.core.biz.model.ReturnT; import com.xxl.job.core.biz.model.ReturnT;
import java.lang.reflect.InvocationTargetException;
/** /**
* job handler * job handler
* *
@ -31,7 +33,7 @@ public abstract class IJobHandler {
/** /**
* init handler, invoked when JobThread init * init handler, invoked when JobThread init
*/ */
public void init() { public void init() throws InvocationTargetException, IllegalAccessException {
// do something // do something
} }
@ -39,7 +41,7 @@ public abstract class IJobHandler {
/** /**
* destroy handler, invoked when JobThread destroy * destroy handler, invoked when JobThread destroy
*/ */
public void destroy() { public void destroy() throws InvocationTargetException, IllegalAccessException {
// do something // do something
} }

View File

@ -8,23 +8,16 @@ import java.lang.annotation.Target;
/** /**
* annotation for job handler * annotation for job handler
*
*
* @author 2016-5-17 21:06:49 * @author 2016-5-17 21:06:49
* @author liuzh 2019-12-07
*/ */
@Target({ElementType.TYPE, ElementType.METHOD}) @Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Inherited @Inherited
@Deprecated
public @interface JobHandler { public @interface JobHandler {
String value() default ""; String value() default "";
/**
* init handler, invoked when JobThread init
*/
String init() default "";
/**
* destroy handler, invoked when JobThread destroy
*/
String destroy() default "";
} }

View File

@ -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 "";
}

View File

@ -6,6 +6,7 @@ import com.xxl.job.core.log.XxlJobLogger;
/** /**
* glue job handler * glue job handler
*
* @author xuxueli 2016-5-19 21:05:45 * @author xuxueli 2016-5-19 21:05:45
*/ */
public class GlueJobHandler extends IJobHandler { public class GlueJobHandler extends IJobHandler {

View File

@ -2,52 +2,26 @@ package com.xxl.job.core.handler.impl;
import com.xxl.job.core.biz.model.ReturnT; import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.handler.IJobHandler; 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.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
/** /**
* @author liuzh 2019-12-07 * @author xuxueli 2019-12-11 21:12:18
*/ */
public class MethodJobHandler extends IJobHandler { public class MethodJobHandler extends IJobHandler {
private static Logger logger = LoggerFactory.getLogger(MethodJobHandler.class);
private final Object target; private final Object target;
private final Method method; private final Method method;
private final JobHandler jobHandler;
private Method initMethod; private Method initMethod;
private Method destroyMethod; 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.target = target;
this.method = method; this.method = method;
this.jobHandler = jobHandler;
this.method.setAccessible(true);
this.prepareMethod();
}
protected void prepareMethod() { this.initMethod =initMethod;
String init = jobHandler.init(); this.destroyMethod =destroyMethod;
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);
}
}
} }
@Override @Override
@ -56,42 +30,21 @@ public class MethodJobHandler extends IJobHandler {
} }
@Override @Override
public void init() { public void init() throws InvocationTargetException, IllegalAccessException {
super.init();
if(initMethod != null) { if(initMethod != null) {
try {
initMethod.invoke(target); initMethod.invoke(target);
} catch (IllegalAccessException e) {
logger.warn(e.getMessage(), e);
} catch (InvocationTargetException e) {
logger.warn(e.getMessage(), e);
}
} }
} }
@Override @Override
public void destroy() { public void destroy() throws InvocationTargetException, IllegalAccessException {
super.destroy();
if(destroyMethod != null) { if(destroyMethod != null) {
try {
destroyMethod.invoke(target); destroyMethod.invoke(target);
} catch (IllegalAccessException e) {
logger.warn(e.getMessage(), e);
} catch (InvocationTargetException e) {
logger.warn(e.getMessage(), e);
}
} }
} }
public Object getTarget() { @Override
return target; public String toString() {
} return super.toString()+"["+ target.getClass() + "#" + method.getName() +"]";
public Method getMethod() {
return method;
}
public JobHandler getJobHandler() {
return jobHandler;
} }
} }

View File

@ -10,6 +10,8 @@ import java.util.concurrent.TimeUnit;
/** /**
* 类方式任务开发即将废弃建议采用方法方式开发参考com.xxl.job.executor.service.jobhandler.SampleXxlJob
*
* 任务Handler示例Bean模式 * 任务Handler示例Bean模式
* *
* 开发步骤 * 开发步骤

View File

@ -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<String> 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<String> execute(String param) {
XxlJobLogger.log("222");
return ReturnT.SUCCESS;
}
@XxlJob(value="demoJobHandler3", init = "init", destroy = "destory")
public ReturnT<String> execute3(String param) {
XxlJobLogger.log("333");
return ReturnT.SUCCESS;
}
public void init(){
System.out.println("init");
}
public void destory(){
System.out.println("destory");
}
}