From df2b9f7e0ca7d124f656b8f66748cdcb5c0d7d1a Mon Sep 17 00:00:00 2001 From: xuxueli <931591021@qq.com> Date: Thu, 1 Nov 2018 10:35:54 +0800 Subject: [PATCH] =?UTF-8?q?-=20=E7=BB=84=E4=BB=B6=E5=8C=96=E4=BC=98?= =?UTF-8?q?=E5=8C=96=EF=BC=8C=E7=A7=BB=E9=99=A4=E5=AF=B9=20spring=20?= =?UTF-8?q?=E7=9A=84=E4=BE=9D=E8=B5=96=EF=BC=9A=E9=9D=9Espring=E5=BA=94?= =?UTF-8?q?=E7=94=A8=E9=80=89=E7=94=A8=20"XxlJobExecutor"=20=E3=80=81sprin?= =?UTF-8?q?g=E5=BA=94=E7=94=A8=E9=80=89=E7=94=A8=20"XxlJobSpringExecutor"?= =?UTF-8?q?=20=E4=BD=9C=E4=B8=BA=E6=89=A7=E8=A1=8C=E5=99=A8=E7=BB=84?= =?UTF-8?q?=E4=BB=B6=EF=BC=9B=20-=20=E4=BB=BB=E5=8A=A1RollingLog=E5=B1=95?= =?UTF-8?q?=E7=A4=BA=E9=80=BB=E8=BE=91=E4=BC=98=E5=8C=96=EF=BC=8C=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=E8=B6=85=E6=97=B6=E4=BB=BB=E5=8A=A1=E6=97=A0=E6=B3=95?= =?UTF-8?q?=E6=9F=A5=E7=9C=8B=E7=9A=84=E9=97=AE=E9=A2=98=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/XXL-JOB官方文档.md | 14 +-- .../job/admin/core/trigger/XxlJobTrigger.java | 3 +- .../resources/static/js/joblog.detail.1.js | 2 +- .../resources/static/js/joblog.index.1.js | 2 +- xxl-job-core/pom.xml | 15 +-- .../xxl/job/core/executor/XxlJobExecutor.java | 42 +------- .../executor/impl/XxlJobSpringExecutor.java | 67 ++++++++++++ .../com/xxl/job/core/glue/GlueFactory.java | 100 ++++++------------ .../job/core/glue/impl/SpringGlueFactory.java | 80 ++++++++++++++ .../resources/applicationcontext-xxl-job.xml | 2 +- .../executor/core/config/XxlJobConfig.java | 22 ++-- 11 files changed, 213 insertions(+), 136 deletions(-) create mode 100644 xxl-job-core/src/main/java/com/xxl/job/core/executor/impl/XxlJobSpringExecutor.java create mode 100644 xxl-job-core/src/main/java/com/xxl/job/core/glue/impl/SpringGlueFactory.java diff --git a/doc/XXL-JOB官方文档.md b/doc/XXL-JOB官方文档.md index 06547681..001259a0 100644 --- a/doc/XXL-JOB官方文档.md +++ b/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 diff --git a/xxl-job-admin/src/main/java/com/xxl/job/admin/core/trigger/XxlJobTrigger.java b/xxl-job-admin/src/main/java/com/xxl/job/admin/core/trigger/XxlJobTrigger.java index 5afacd79..f6115ea9 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/admin/core/trigger/XxlJobTrigger.java +++ b/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(ReturnT.FAIL_CODE, ""+e ); + runResult = new ReturnT(ReturnT.FAIL_CODE, ThrowableUtil.toString(e)); } StringBuffer runResultSB = new StringBuffer(I18nUtil.getString("jobconf_trigger_run") + ":"); diff --git a/xxl-job-admin/src/main/resources/static/js/joblog.detail.1.js b/xxl-job-admin/src/main/resources/static/js/joblog.detail.1.js index 0f556d66..ddefd466 100644 --- a/xxl-job-admin/src/main/resources/static/js/joblog.detail.1.js +++ b/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(''+ I18n.joblog_rolling_log_triggerfail +''); return; diff --git a/xxl-job-admin/src/main/resources/static/js/joblog.index.1.js b/xxl-job-admin/src/main/resources/static/js/joblog.index.1.js index 55913d15..c8b58f68 100644 --- a/xxl-job-admin/src/main/resources/static/js/joblog.index.1.js +++ b/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 = ''+ I18n.joblog_rolling_log +''; if(row.handleCode == 0){ temp += '
'+ I18n.joblog_kill_log +''; diff --git a/xxl-job-core/pom.xml b/xxl-job-core/pom.xml index f5306a84..9997bc5a 100644 --- a/xxl-job-core/pom.xml +++ b/xxl-job-core/pom.xml @@ -36,13 +36,6 @@ ${commons-exec.version} - - - org.springframework - spring-context - ${spring.version} - - com.fasterxml.jackson.core @@ -50,6 +43,14 @@ ${jackson.version} + + + org.springframework + spring-context + ${spring.version} + provided + + \ No newline at end of file diff --git a/xxl-job-core/src/main/java/com/xxl/job/core/executor/XxlJobExecutor.java b/xxl-job-core/src/main/java/com/xxl/job/core/executor/XxlJobExecutor.java index aee94f9f..0f06b10f 100644 --- a/xxl-job-core/src/main/java/com/xxl/job/core/executor/XxlJobExecutor.java +++ b/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 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 ---------------------- 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 new file mode 100644 index 00000000..cbe16a82 --- /dev/null +++ b/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 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; + } + +} diff --git a/xxl-job-core/src/main/java/com/xxl/job/core/glue/GlueFactory.java b/xxl-job-core/src/main/java/com/xxl/job/core/glue/GlueFactory.java index 400cfc09..8b9e8cd2 100644 --- a/xxl-job-core/src/main/java/com/xxl/job/core/glue/GlueFactory.java +++ b/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); - + + + 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(); + } + } + + /** * groovy class loader */ private GroovyClassLoader groovyClassLoader = new GroovyClassLoader(); - // ----------------------------- spring support ----------------------------- - private static GlueFactory glueFactory = new GlueFactory(); - public static GlueFactory getInstance(){ - return glueFactory; - } /** - * inject action of spring - * @param instance + * 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 + } + } diff --git a/xxl-job-core/src/main/java/com/xxl/job/core/glue/impl/SpringGlueFactory.java b/xxl-job-core/src/main/java/com/xxl/job/core/glue/impl/SpringGlueFactory.java new file mode 100644 index 00000000..37e44d5f --- /dev/null +++ b/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); + } + } + } + } + +} diff --git a/xxl-job-executor-samples/xxl-job-executor-sample-spring/src/main/resources/applicationcontext-xxl-job.xml b/xxl-job-executor-samples/xxl-job-executor-sample-spring/src/main/resources/applicationcontext-xxl-job.xml index 942fb2f0..8e06118c 100644 --- a/xxl-job-executor-samples/xxl-job-executor-sample-spring/src/main/resources/applicationcontext-xxl-job.xml +++ b/xxl-job-executor-samples/xxl-job-executor-sample-spring/src/main/resources/applicationcontext-xxl-job.xml @@ -22,7 +22,7 @@ - + diff --git a/xxl-job-executor-samples/xxl-job-executor-sample-springboot/src/main/java/com/xxl/job/executor/core/config/XxlJobConfig.java b/xxl-job-executor-samples/xxl-job-executor-sample-springboot/src/main/java/com/xxl/job/executor/core/config/XxlJobConfig.java index a90e43e1..60be51e1 100644 --- a/xxl-job-executor-samples/xxl-job-executor-sample-springboot/src/main/java/com/xxl/job/executor/core/config/XxlJobConfig.java +++ b/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); + 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 xxlJobExecutor; + return xxlJobSpringExecutor; } } \ No newline at end of file