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

master
xuxueli 5 years ago
parent 49f7e16954
commit f083bb2695
  1. 17
      doc/XXL-JOB官方文档.md
  2. 58
      xxl-job-core/src/main/java/com/xxl/job/core/executor/impl/XxlJobSpringExecutor.java
  3. 6
      xxl-job-core/src/main/java/com/xxl/job/core/handler/IJobHandler.java
  4. 15
      xxl-job-core/src/main/java/com/xxl/job/core/handler/annotation/JobHandler.java
  5. 30
      xxl-job-core/src/main/java/com/xxl/job/core/handler/annotation/XxlJob.java
  6. 1
      xxl-job-core/src/main/java/com/xxl/job/core/handler/impl/GlueJobHandler.java
  7. 65
      xxl-job-core/src/main/java/com/xxl/job/core/handler/impl/MethodJobHandler.java
  8. 2
      xxl-job-executor-samples/xxl-job-executor-sample-springboot/src/main/java/com/xxl/job/executor/service/jobhandler/DemoJobHandler.java
  9. 44
      xxl-job-executor-samples/xxl-job-executor-sample-springboot/src/main/java/com/xxl/job/executor/service/jobhandler/SampleXxlJob.java

@ -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<String> execute(String param) {
XxlJobLogger.log("hello world");
return ReturnT.SUCCESS;
}
```
- 2、调度中心dispatcher servlet加载顺序优化;
- 3、执行器回调乱码问题修复;
- 4、[迭代中]移除commons-exec,采用原生方式实现;
- 5、[迭代中]任务操作API服务调整为restful方式,降低接入成本;
### TODO LIST

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

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

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

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

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

@ -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);
}
}
}
@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);
}
}
}
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() +"]";
}
}

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

@ -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");
}
}
Loading…
Cancel
Save