Browse Source

- 组件化优化,移除对 spring 的依赖:非spring应用选用 "XxlJobExecutor" 、spring应用选用 "XxlJobSpringExecutor" 作为执行器组件;
- 任务RollingLog展示逻辑优化,修复超时任务无法查看的问题;

xuxueli 6 years ago
parent
commit
df2b9f7e0c

+ 8 - 6
doc/XXL-JOB官方文档.md

@@ -1328,12 +1328,14 @@ Tips: 历史版本(V1.3.x)目前已经Release至稳定版本, 进入维护阶段
 - 2、底层通讯组件迁移至 xxl-rpc;
 - 3、IP获取逻辑优化,优先遍历网卡来获取可用IP;
 - 4、任务新增的API服务接口返回任务ID,方便调用方实用;
-- 5、新增无框架执行器Sample示例项目 "xxl-job-executor-sample-frameless"。不依赖第三方框架,只需main方法即可启动运行执行器;
-- 6、[迭代中]任务状态与quartz解耦,降低quartz调度压力,仅NORMAL状态任务绑定quartz;
-- 7、[迭代中]新增任务默认运行状态,任务更新时运行状态保持不变;
-- 8、[迭代中]原生提供通用命令行任务Handler(Bean任务,"CommandJobHandler");业务方只需要提供命令行即可,可执行任意命令;
-- 9、[迭代中]cron在线生成工具,如 "cronboot/cron.qqe2";
-- 10、[迭代中]docker镜像,并且推送docker镜像到中央仓库,更进一步实现产品开箱即用;
+- 5、组件化优化,移除对 spring 的依赖:非spring应用选用 "XxlJobExecutor" 、spring应用选用 "XxlJobSpringExecutor" 作为执行器组件; 
+- 6、新增无框架执行器Sample示例项目 "xxl-job-executor-sample-frameless"。不依赖第三方框架,只需main方法即可启动运行执行器;
+- 7、任务RollingLog展示逻辑优化,修复超时任务无法查看的问题;
+- 8、[迭代中]任务状态与quartz解耦,降低quartz调度压力,仅NORMAL状态任务绑定quartz;
+- 9、[迭代中]新增任务默认运行状态,任务更新时运行状态保持不变;
+- 10、[迭代中]原生提供通用命令行任务Handler(Bean任务,"CommandJobHandler");业务方只需要提供命令行即可,可执行任意命令;
+- 11、[迭代中]cron在线生成工具,如 "cronboot/cron.qqe2";
+- 12、[迭代中]docker镜像,并且推送docker镜像到中央仓库,更进一步实现产品开箱即用;
 
 
 ### TODO LIST

+ 2 - 1
xxl-job-admin/src/main/java/com/xxl/job/admin/core/trigger/XxlJobTrigger.java

@@ -13,6 +13,7 @@ import com.xxl.job.core.biz.model.ReturnT;
 import com.xxl.job.core.biz.model.TriggerParam;
 import com.xxl.job.core.enums.ExecutorBlockStrategyEnum;
 import com.xxl.rpc.util.IpUtil;
+import com.xxl.rpc.util.ThrowableUtil;
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.slf4j.Logger;
@@ -190,7 +191,7 @@ public class XxlJobTrigger {
             runResult = executorBiz.run(triggerParam);
         } catch (Exception e) {
             logger.error(">>>>>>>>>>> xxl-job trigger error, please check if the executor[{}] is running.", address, e);
-            runResult = new ReturnT<String>(ReturnT.FAIL_CODE, ""+e );
+            runResult = new ReturnT<String>(ReturnT.FAIL_CODE, ThrowableUtil.toString(e));
         }
 
         StringBuffer runResultSB = new StringBuffer(I18nUtil.getString("jobconf_trigger_run") + ":");

+ 1 - 1
xxl-job-admin/src/main/resources/static/js/joblog.detail.1.js

@@ -1,7 +1,7 @@
 $(function() {
 
     // trigger fail, end
-    if (triggerCode != 200) {
+    if ( !(triggerCode == 200 || handleCode != 0) ) {
         $('#logConsoleRunning').hide();
         $('#logConsole').append('<span style="color: red;">'+ I18n.joblog_rolling_log_triggerfail +'</span>');
         return;

+ 1 - 1
xxl-job-admin/src/main/resources/static/js/joblog.index.1.js

@@ -179,7 +179,7 @@ $(function() {
 	                	"render": function ( data, type, row ) {
 	                		// better support expression or string, not function
 	                		return function () {
-		                		if (row.triggerCode == 200){
+		                		if (row.triggerCode == 200 || row.handleCode != 0){
 		                			var temp = '<a href="javascript:;" class="logDetail" _id="'+ row.id +'">'+ I18n.joblog_rolling_log +'</a>';
 		                			if(row.handleCode == 0){
 		                				temp += '<br><a href="javascript:;" class="logKill" _id="'+ row.id +'" style="color: red;" >'+ I18n.joblog_kill_log +'</a>';

+ 8 - 7
xxl-job-core/pom.xml

@@ -36,13 +36,6 @@
 			<version>${commons-exec.version}</version>
 		</dependency>
 
-		<!-- spring-context -->
-		<dependency>
-			<groupId>org.springframework</groupId>
-			<artifactId>spring-context</artifactId>
-			<version>${spring.version}</version>
-		</dependency>
-
 		<!-- jackson -->
 		<dependency>
 			<groupId>com.fasterxml.jackson.core</groupId>
@@ -50,6 +43,14 @@
 			<version>${jackson.version}</version>
 		</dependency>
 
+		<!-- spring-context -->
+		<dependency>
+			<groupId>org.springframework</groupId>
+			<artifactId>spring-context</artifactId>
+			<version>${spring.version}</version>
+			<scope>provided</scope>
+		</dependency>
+
 	</dependencies>
 
 </project>

+ 3 - 39
xxl-job-core/src/main/java/com/xxl/job/core/executor/XxlJobExecutor.java

@@ -4,7 +4,6 @@ import com.xxl.job.core.biz.AdminBiz;
 import com.xxl.job.core.biz.ExecutorBiz;
 import com.xxl.job.core.biz.impl.ExecutorBizImpl;
 import com.xxl.job.core.handler.IJobHandler;
-import com.xxl.job.core.handler.annotation.JobHandler;
 import com.xxl.job.core.log.XxlJobFileAppender;
 import com.xxl.job.core.thread.ExecutorRegistryThread;
 import com.xxl.job.core.thread.JobLogFileCleanThread;
@@ -21,9 +20,6 @@ import com.xxl.rpc.util.IpUtil;
 import com.xxl.rpc.util.NetUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.springframework.beans.BeansException;
-import org.springframework.context.ApplicationContext;
-import org.springframework.context.ApplicationContextAware;
 
 import java.util.*;
 import java.util.concurrent.ConcurrentHashMap;
@@ -31,7 +27,7 @@ import java.util.concurrent.ConcurrentHashMap;
 /**
  * Created by xuxueli on 2016/3/2 21:14.
  */
-public class XxlJobExecutor implements ApplicationContextAware {
+public class XxlJobExecutor  {
     private static final Logger logger = LoggerFactory.getLogger(XxlJobExecutor.class);
 
     // ---------------------- param ----------------------
@@ -65,16 +61,6 @@ public class XxlJobExecutor implements ApplicationContextAware {
         this.logRetentionDays = logRetentionDays;
     }
 
-    // ---------------------- applicationContext ----------------------
-    private static ApplicationContext applicationContext;
-    @Override
-    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
-        this.applicationContext = applicationContext;
-    }
-    public static ApplicationContext getApplicationContext() {
-        return applicationContext;
-    }
-
 
     // ---------------------- start + stop ----------------------
     public void start() throws Exception {
@@ -82,12 +68,10 @@ public class XxlJobExecutor implements ApplicationContextAware {
         // init logpath
         XxlJobFileAppender.initLogPath(logPath);
 
-        // init JobHandler Repository
-        initJobHandlerRepository(applicationContext);
-
         // init admin-client
         initAdminBizList(adminAddresses, accessToken);
 
+
         // init JobLogFileCleanThread
         JobLogFileCleanThread.getInstance().start(logRetentionDays);
 
@@ -108,6 +92,7 @@ public class XxlJobExecutor implements ApplicationContextAware {
             jobThreadRepository.clear();
         }
 
+
         // destory JobLogFileCleanThread
         JobLogFileCleanThread.getInstance().toStop();
 
@@ -228,27 +213,6 @@ public class XxlJobExecutor implements ApplicationContextAware {
     public static IJobHandler loadJobHandler(String name){
         return jobHandlerRepository.get(name);
     }
-    private void initJobHandlerRepository(ApplicationContext applicationContext){
-        if (applicationContext == null) {
-            return;
-        }
-
-        // init job handler action
-        Map<String, Object> serviceBeanMap = applicationContext.getBeansWithAnnotation(JobHandler.class);
-
-        if (serviceBeanMap!=null && serviceBeanMap.size()>0) {
-            for (Object serviceBean : serviceBeanMap.values()) {
-                if (serviceBean instanceof IJobHandler){
-                    String name = serviceBean.getClass().getAnnotation(JobHandler.class).value();
-                    IJobHandler handler = (IJobHandler) serviceBean;
-                    if (loadJobHandler(name) != null) {
-                        throw new RuntimeException("xxl-job jobhandler naming conflicts.");
-                    }
-                    registJobHandler(name, handler);
-                }
-            }
-        }
-    }
 
 
     // ---------------------- job thread repository ----------------------

+ 67 - 0
xxl-job-core/src/main/java/com/xxl/job/core/executor/impl/XxlJobSpringExecutor.java

@@ -0,0 +1,67 @@
+package com.xxl.job.core.executor.impl;
+
+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 org.springframework.beans.BeansException;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+
+import java.util.Map;
+
+/**
+ * xxl-job executor (for spring)
+ *
+ * @author xuxueli 2018-11-01 09:24:52
+ */
+public class XxlJobSpringExecutor extends XxlJobExecutor implements ApplicationContextAware {
+
+
+    @Override
+    public void start() throws Exception {
+
+        // init JobHandler Repository
+        initJobHandlerRepository(applicationContext);
+
+        // refresh GlueFactory
+        GlueFactory.refreshInstance(1);
+
+
+        // super start
+        super.start();
+    }
+
+    private void initJobHandlerRepository(ApplicationContext applicationContext){
+        if (applicationContext == null) {
+            return;
+        }
+
+        // init job handler action
+        Map<String, Object> serviceBeanMap = applicationContext.getBeansWithAnnotation(JobHandler.class);
+
+        if (serviceBeanMap!=null && serviceBeanMap.size()>0) {
+            for (Object serviceBean : serviceBeanMap.values()) {
+                if (serviceBean instanceof IJobHandler){
+                    String name = serviceBean.getClass().getAnnotation(JobHandler.class).value();
+                    IJobHandler handler = (IJobHandler) serviceBean;
+                    if (loadJobHandler(name) != null) {
+                        throw new RuntimeException("xxl-job jobhandler naming conflicts.");
+                    }
+                    registJobHandler(name, handler);
+                }
+            }
+        }
+    }
+
+    // ---------------------- applicationContext ----------------------
+    private static ApplicationContext applicationContext;
+    @Override
+    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+        this.applicationContext = applicationContext;
+    }
+    public static ApplicationContext getApplicationContext() {
+        return applicationContext;
+    }
+
+}

+ 31 - 69
xxl-job-core/src/main/java/com/xxl/job/core/glue/GlueFactory.java

@@ -1,90 +1,43 @@
 package com.xxl.job.core.glue;
 
-import com.xxl.job.core.executor.XxlJobExecutor;
+import com.xxl.job.core.glue.impl.SpringGlueFactory;
 import com.xxl.job.core.handler.IJobHandler;
 import groovy.lang.GroovyClassLoader;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Qualifier;
-import org.springframework.core.annotation.AnnotationUtils;
-
-import javax.annotation.Resource;
-import java.lang.reflect.Field;
-import java.lang.reflect.Modifier;
 
 /**
  * glue factory, product class/object by name
+ *
  * @author xuxueli 2016-1-2 20:02:27
  */
 public class GlueFactory {
-	private static Logger logger = LoggerFactory.getLogger(GlueFactory.class);
-	
-	/**
-	 * groovy class loader
-	 */
-	private GroovyClassLoader groovyClassLoader = new GroovyClassLoader();
 
-	// ----------------------------- spring support -----------------------------
+
 	private static GlueFactory glueFactory = new GlueFactory();
 	public static GlueFactory getInstance(){
 		return glueFactory;
 	}
+	public static void refreshInstance(int type){
+		if (type == 0) {
+			glueFactory = new GlueFactory();
+		} else if (type == 1) {
+			glueFactory = new SpringGlueFactory();
+		}
+	}
+
 
 	/**
-	 * inject action of spring
-	 * @param instance
+	 * groovy class loader
+	 */
+	private GroovyClassLoader groovyClassLoader = new GroovyClassLoader();
+
+
+	/**
+	 * load new instance, prototype
+	 *
+	 * @param codeSource
+	 * @return
+	 * @throws Exception
 	 */
-	private void injectService(Object instance){
-		if (instance==null) {
-			return;
-		}
-	    
-		Field[] fields = instance.getClass().getDeclaredFields();
-		for (Field field : fields) {
-			if (Modifier.isStatic(field.getModifiers())) {
-				continue;
-			}
-			
-			Object fieldBean = null;
-			// with bean-id, bean could be found by both @Resource and @Autowired, or bean could only be found by @Autowired
-			if (AnnotationUtils.getAnnotation(field, Resource.class) != null) {
-				try {
-					Resource resource = AnnotationUtils.getAnnotation(field, Resource.class);
-					if (resource.name()!=null && resource.name().length()>0){
-						fieldBean = XxlJobExecutor.getApplicationContext().getBean(resource.name());
-					} else {
-						fieldBean = XxlJobExecutor.getApplicationContext().getBean(field.getName());
-					}
-				} catch (Exception e) {
-				}
-				if (fieldBean==null ) {
-					fieldBean = XxlJobExecutor.getApplicationContext().getBean(field.getType());
-				}
-			} else if (AnnotationUtils.getAnnotation(field, Autowired.class) != null) {
-				Qualifier qualifier = AnnotationUtils.getAnnotation(field, Qualifier.class);
-				if (qualifier!=null && qualifier.value()!=null && qualifier.value().length()>0) {
-					fieldBean = XxlJobExecutor.getApplicationContext().getBean(qualifier.value());
-				} else {
-					fieldBean = XxlJobExecutor.getApplicationContext().getBean(field.getType());
-				}
-			}
-			
-			if (fieldBean!=null) {
-				field.setAccessible(true);
-				try {
-					field.set(instance, fieldBean);
-				} catch (IllegalArgumentException e) {
-					logger.error(e.getMessage(), e);
-				} catch (IllegalAccessException e) {
-					logger.error(e.getMessage(), e);
-				}
-			}
-		}
-	}
-	
-	// ----------------------------- load instance -----------------------------
-	// load new instance, prototype
 	public IJobHandler loadNewInstance(String codeSource) throws Exception{
 		if (codeSource!=null && codeSource.trim().length()>0) {
 			Class<?> clazz = groovyClassLoader.parseClass(codeSource);
@@ -104,4 +57,13 @@ public class GlueFactory {
 		throw new IllegalArgumentException(">>>>>>>>>>> xxl-glue, loadNewInstance error, instance is null");
 	}
 
+	/**
+	 * inject service of bean field
+	 *
+	 * @param instance
+	 */
+	public void injectService(Object instance) {
+		// do something
+	}
+
 }

+ 80 - 0
xxl-job-core/src/main/java/com/xxl/job/core/glue/impl/SpringGlueFactory.java

@@ -0,0 +1,80 @@
+package com.xxl.job.core.glue.impl;
+
+import com.xxl.job.core.executor.impl.XxlJobSpringExecutor;
+import com.xxl.job.core.glue.GlueFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.core.annotation.AnnotationUtils;
+
+import javax.annotation.Resource;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+
+/**
+ * @author xuxueli 2018-11-01
+ */
+public class SpringGlueFactory extends GlueFactory {
+    private static Logger logger = LoggerFactory.getLogger(SpringGlueFactory.class);
+
+
+    /**
+     * inject action of spring
+     * @param instance
+     */
+    @Override
+    public void injectService(Object instance){
+        if (instance==null) {
+            return;
+        }
+
+        if (XxlJobSpringExecutor.getApplicationContext() == null) {
+            return;
+        }
+
+        Field[] fields = instance.getClass().getDeclaredFields();
+        for (Field field : fields) {
+            if (Modifier.isStatic(field.getModifiers())) {
+                continue;
+            }
+
+            Object fieldBean = null;
+            // with bean-id, bean could be found by both @Resource and @Autowired, or bean could only be found by @Autowired
+
+            if (AnnotationUtils.getAnnotation(field, Resource.class) != null) {
+                try {
+                    Resource resource = AnnotationUtils.getAnnotation(field, Resource.class);
+                    if (resource.name()!=null && resource.name().length()>0){
+                        fieldBean = XxlJobSpringExecutor.getApplicationContext().getBean(resource.name());
+                    } else {
+                        fieldBean = XxlJobSpringExecutor.getApplicationContext().getBean(field.getName());
+                    }
+                } catch (Exception e) {
+                }
+                if (fieldBean==null ) {
+                    fieldBean = XxlJobSpringExecutor.getApplicationContext().getBean(field.getType());
+                }
+            } else if (AnnotationUtils.getAnnotation(field, Autowired.class) != null) {
+                Qualifier qualifier = AnnotationUtils.getAnnotation(field, Qualifier.class);
+                if (qualifier!=null && qualifier.value()!=null && qualifier.value().length()>0) {
+                    fieldBean = XxlJobSpringExecutor.getApplicationContext().getBean(qualifier.value());
+                } else {
+                    fieldBean = XxlJobSpringExecutor.getApplicationContext().getBean(field.getType());
+                }
+            }
+
+            if (fieldBean!=null) {
+                field.setAccessible(true);
+                try {
+                    field.set(instance, fieldBean);
+                } catch (IllegalArgumentException e) {
+                    logger.error(e.getMessage(), e);
+                } catch (IllegalAccessException e) {
+                    logger.error(e.getMessage(), e);
+                }
+            }
+        }
+    }
+
+}

+ 1 - 1
xxl-job-executor-samples/xxl-job-executor-sample-spring/src/main/resources/applicationcontext-xxl-job.xml

@@ -22,7 +22,7 @@
 	<context:component-scan base-package="com.xxl.job.executor.service.jobhandler" />
 
 	<!-- 配置02、执行器 -->
-	<bean id="xxlJobExecutor" class="com.xxl.job.core.executor.XxlJobExecutor" init-method="start" destroy-method="destroy" >
+	<bean id="xxlJobSpringExecutor" class="com.xxl.job.core.executor.impl.XxlJobSpringExecutor" init-method="start" destroy-method="destroy" >
 		<!-- 执行器注册中心地址[选填],为空则关闭自动注册 -->
 		<property name="adminAddresses" value="${xxl.job.admin.addresses}" />
 		<!-- 执行器AppName[选填],为空则关闭自动注册 -->

+ 12 - 12
xxl-job-executor-samples/xxl-job-executor-sample-springboot/src/main/java/com/xxl/job/executor/core/config/XxlJobConfig.java

@@ -1,6 +1,6 @@
 package com.xxl.job.executor.core.config;
 
-import com.xxl.job.core.executor.XxlJobExecutor;
+import com.xxl.job.core.executor.impl.XxlJobSpringExecutor;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Value;
@@ -41,18 +41,18 @@ public class XxlJobConfig {
 
 
     @Bean(initMethod = "start", destroyMethod = "destroy")
-    public XxlJobExecutor xxlJobExecutor() {
+    public XxlJobSpringExecutor xxlJobExecutor() {
         logger.info(">>>>>>>>>>> xxl-job config init.");
-        XxlJobExecutor xxlJobExecutor = new XxlJobExecutor();
-        xxlJobExecutor.setAdminAddresses(adminAddresses);
-        xxlJobExecutor.setAppName(appName);
-        xxlJobExecutor.setIp(ip);
-        xxlJobExecutor.setPort(port);
-        xxlJobExecutor.setAccessToken(accessToken);
-        xxlJobExecutor.setLogPath(logPath);
-        xxlJobExecutor.setLogRetentionDays(logRetentionDays);
-
-        return xxlJobExecutor;
+        XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();
+        xxlJobSpringExecutor.setAdminAddresses(adminAddresses);
+        xxlJobSpringExecutor.setAppName(appName);
+        xxlJobSpringExecutor.setIp(ip);
+        xxlJobSpringExecutor.setPort(port);
+        xxlJobSpringExecutor.setAccessToken(accessToken);
+        xxlJobSpringExecutor.setLogPath(logPath);
+        xxlJobSpringExecutor.setLogRetentionDays(logRetentionDays);
+
+        return xxlJobSpringExecutor;
     }
 
 }