Browse Source

新增无框架执行器Sample示例项目 "xxl-job-executor-sample-frameless"。不依赖第三方框架,只需main方法即可启动运行执行器;

xuxueli 6 years ago
parent
commit
af6c46743f

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

@@ -1328,11 +1328,12 @@ Tips: 历史版本(V1.3.x)目前已经Release至稳定版本, 进入维护阶段
 - 2、底层通讯组件迁移至 xxl-rpc;
 - 3、IP获取逻辑优化,优先遍历网卡来获取可用IP;
 - 4、任务新增的API服务接口返回任务ID,方便调用方实用;
-- 5、[迭代中]任务状态与quartz解耦,降低quartz调度压力,仅NORMAL状态任务绑定quartz;
-- 6、[迭代中]新增任务默认运行状态,任务更新时运行状态保持不变;
-- 7、[迭代中]原生提供通用命令行任务Handler(Bean任务,"CommandJobHandler");业务方只需要提供命令行即可,可执行任意命令;
-- 8、[迭代中]cron在线生成工具,如 "cronboot/cron.qqe2";
-- 9、[迭代中]docker镜像,并且推送docker镜像到中央仓库,更进一步实现产品开箱即用;
+- 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镜像到中央仓库,更进一步实现产品开箱即用;
 
 
 ### TODO LIST
@@ -1359,8 +1360,8 @@ Tips: 历史版本(V1.3.x)目前已经Release至稳定版本, 进入维护阶段
 - 21、批量触发支持,添加参数 "org.quartz.scheduler.batchTriggerAcquisitionMaxCount: 50";
 - 22、失败重试间隔;
 - 23、Release发布时,一同发布调度中心安装包,真正实现开箱即用;
-- 24、[迭代中]任务权限管理:执行器为粒度分配权限,核心操作校验权限;
-- 25、[迭代中]SimpleTrigger 支持;
+- 24、任务权限管理:执行器为粒度分配权限,核心操作校验权限;
+- 25、SimpleTrigger 支持;
 
 
 ## 七、其他

+ 29 - 18
xxl-job-core/src/main/java/com/xxl/job/core/executor/XxlJobExecutor.java

@@ -10,7 +10,7 @@ import com.xxl.job.core.thread.ExecutorRegistryThread;
 import com.xxl.job.core.thread.JobLogFileCleanThread;
 import com.xxl.job.core.thread.JobThread;
 import com.xxl.job.core.thread.TriggerCallbackThread;
-import com.xxl.rpc.registry.impl.LocalServiceRegistry;
+import com.xxl.rpc.registry.ServiceRegistry;
 import com.xxl.rpc.remoting.invoker.XxlRpcInvokerFactory;
 import com.xxl.rpc.remoting.invoker.call.CallType;
 import com.xxl.rpc.remoting.invoker.reference.XxlRpcReferenceBean;
@@ -25,9 +25,7 @@ import org.springframework.beans.BeansException;
 import org.springframework.context.ApplicationContext;
 import org.springframework.context.ApplicationContextAware;
 
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 import java.util.concurrent.ConcurrentHashMap;
 
 /**
@@ -38,7 +36,7 @@ public class XxlJobExecutor implements ApplicationContextAware {
 
     // ---------------------- param ----------------------
     private String adminAddresses;
-    private static String appName;
+    private String appName;
     private String ip;
     private int port;
     private String accessToken;
@@ -123,7 +121,7 @@ public class XxlJobExecutor implements ApplicationContextAware {
 
     // ---------------------- admin-client (rpc invoker) ----------------------
     private static List<AdminBiz> adminBizList;
-    private static void initAdminBizList(String adminAddresses, String accessToken) throws Exception {
+    private void initAdminBizList(String adminAddresses, String accessToken) throws Exception {
         if (adminAddresses!=null && adminAddresses.trim().length()>0) {
             for (String address: adminAddresses.trim().split(",")) {
                 if (address!=null && address.trim().length()>0) {
@@ -155,13 +153,19 @@ public class XxlJobExecutor implements ApplicationContextAware {
     // ---------------------- executor-server (rpc provider) ----------------------
     private XxlRpcInvokerFactory xxlRpcInvokerFactory = null;
     private XxlRpcProviderFactory xxlRpcProviderFactory = null;
+
     private void initRpcProvider(String ip, int port, String appName, String accessToken) throws Exception {
         // init invoker factory
         xxlRpcInvokerFactory = new XxlRpcInvokerFactory();
 
         // init, provider factory
+        String address = IpUtil.getIpPort(ip, port);
+        Map<String, String> serviceRegistryParam = new HashMap<String, String>();
+        serviceRegistryParam.put("appName", appName);
+        serviceRegistryParam.put("address", address);
+
         xxlRpcProviderFactory = new XxlRpcProviderFactory();
-        xxlRpcProviderFactory.initConfig(NetEnum.JETTY, Serializer.SerializeEnum.HESSIAN.getSerializer(), ip, port, accessToken, ExecutorServiceRegistry.class, null);
+        xxlRpcProviderFactory.initConfig(NetEnum.JETTY, Serializer.SerializeEnum.HESSIAN.getSerializer(), ip, port, accessToken, ExecutorServiceRegistry.class, serviceRegistryParam);
 
         // add services
         xxlRpcProviderFactory.addService(ExecutorBiz.class.getName(), null, new ExecutorBizImpl());
@@ -171,25 +175,32 @@ public class XxlJobExecutor implements ApplicationContextAware {
 
     }
 
-    public static class ExecutorServiceRegistry extends LocalServiceRegistry {
-        @Override
-        public boolean registry(String key, String value) {
+    public static class ExecutorServiceRegistry extends ServiceRegistry {
 
+        @Override
+        public void start(Map<String, String> param) {
             // start registry
-            if (ExecutorBiz.class.getName().equalsIgnoreCase(key)) {
-                ExecutorRegistryThread.getInstance().start(appName, value);
-            }
-
-            return super.registry(key, value);
+            ExecutorRegistryThread.getInstance().start(param.get("appName"), param.get("address"));
         }
-
         @Override
         public void stop() {
             // stop registry
             ExecutorRegistryThread.getInstance().toStop();
+        }
 
-            super.stop();
+        @Override
+        public boolean registry(String key, String value) {
+            return false;
+        }
+        @Override
+        public boolean remove(String key, String value) {
+            return false;
+        }
+        @Override
+        public TreeSet<String> discovery(String key) {
+            return null;
         }
+
     }
 
     private void stopRpcProvider() {
@@ -217,7 +228,7 @@ public class XxlJobExecutor implements ApplicationContextAware {
     public static IJobHandler loadJobHandler(String name){
         return jobHandlerRepository.get(name);
     }
-    private static void initJobHandlerRepository(ApplicationContext applicationContext){
+    private void initJobHandlerRepository(ApplicationContext applicationContext){
         if (applicationContext == null) {
             return;
         }

+ 1 - 0
xxl-job-executor-samples/pom.xml

@@ -15,6 +15,7 @@
         <module>xxl-job-executor-sample-springboot</module>
         <module>xxl-job-executor-sample-jfinal</module>
         <module>xxl-job-executor-sample-nutz</module>
+        <module>xxl-job-executor-sample-frameless</module>
     </modules>
 
 </project>

+ 37 - 0
xxl-job-executor-samples/xxl-job-executor-sample-frameless/pom.xml

@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>com.xuxueli</groupId>
+        <artifactId>xxl-job-executor-samples</artifactId>
+        <version>2.0.0-SNAPSHOT</version>
+    </parent>
+    <artifactId>xxl-job-executor-sample-frameless</artifactId>
+    <packaging>jar</packaging>
+
+    <name>${project.artifactId}</name>
+    <description>Example executor project for spring boot.</description>
+    <url>http://www.xuxueli.com/</url>
+
+
+    <dependencies>
+
+        <!-- slf4j -->
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-log4j12</artifactId>
+            <version>${slf4j-api.version}</version>
+        </dependency>
+
+        <!-- xxl-job-core -->
+        <dependency>
+            <groupId>com.xuxueli</groupId>
+            <artifactId>xxl-job-core</artifactId>
+            <version>${project.parent.version}</version>
+        </dependency>
+    </dependencies>
+
+
+</project>

+ 33 - 0
xxl-job-executor-samples/xxl-job-executor-sample-frameless/src/main/java/com/xuxueli/executor/sample/frameless/Application.java

@@ -0,0 +1,33 @@
+package com.xuxueli.executor.sample.frameless;
+
+import com.xuxueli.executor.sample.frameless.config.FrameLessXxlJobConfig;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @author xuxueli 2018-10-31 19:05:43
+ */
+public class Application {
+    private static Logger logger = LoggerFactory.getLogger(Application.class);
+
+    public static void main(String[] args) {
+
+        try {
+            // start
+            FrameLessXxlJobConfig.getInstance().initXxlJobExecutor();
+
+            while (true) {
+                TimeUnit.HOURS.sleep(1);
+            }
+        } catch (Exception e) {
+            logger.error(e.getMessage(), e);
+        } finally {
+            // destory
+            FrameLessXxlJobConfig.getInstance().destoryXxlJobExecutor();
+        }
+
+    }
+
+}

+ 96 - 0
xxl-job-executor-samples/xxl-job-executor-sample-frameless/src/main/java/com/xuxueli/executor/sample/frameless/config/FrameLessXxlJobConfig.java

@@ -0,0 +1,96 @@
+package com.xuxueli.executor.sample.frameless.config;
+
+import com.xuxueli.executor.sample.frameless.jobhandler.DemoJobHandler;
+import com.xuxueli.executor.sample.frameless.jobhandler.HttpJobHandler;
+import com.xuxueli.executor.sample.frameless.jobhandler.ShardingJobHandler;
+import com.xxl.job.core.executor.XxlJobExecutor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.Properties;
+
+/**
+ * @author xuxueli 2018-10-31 19:05:43
+ */
+public class FrameLessXxlJobConfig {
+    private static Logger logger = LoggerFactory.getLogger(FrameLessXxlJobConfig.class);
+
+
+    private static FrameLessXxlJobConfig instance = new FrameLessXxlJobConfig();
+    public static FrameLessXxlJobConfig getInstance() {
+        return instance;
+    }
+
+
+    private XxlJobExecutor xxlJobExecutor = null;
+
+    /**
+     * init
+     */
+    public void initXxlJobExecutor() {
+
+        // registry jobhandler
+        XxlJobExecutor.registJobHandler("demoJobHandler", new DemoJobHandler());
+        XxlJobExecutor.registJobHandler("shardingJobHandler", new ShardingJobHandler());
+        XxlJobExecutor.registJobHandler("httpJobHandler", new HttpJobHandler());
+
+        // load executor prop
+        Properties xxlJobProp = loadProperties("xxl-job-executor.properties");
+
+
+        // init executor
+        xxlJobExecutor = new XxlJobExecutor();
+        xxlJobExecutor.setAdminAddresses(xxlJobProp.getProperty("xxl.job.admin.addresses"));
+        xxlJobExecutor.setAppName(xxlJobProp.getProperty("xxl.job.executor.appname"));
+        xxlJobExecutor.setIp(xxlJobProp.getProperty("xxl.job.executor.ip"));
+        xxlJobExecutor.setPort(Integer.valueOf(xxlJobProp.getProperty("xxl.job.executor.port")));
+        xxlJobExecutor.setAccessToken(xxlJobProp.getProperty("xxl.job.accessToken"));
+        xxlJobExecutor.setLogPath(xxlJobProp.getProperty("xxl.job.executor.logpath"));
+        xxlJobExecutor.setLogRetentionDays(Integer.valueOf(xxlJobProp.getProperty("xxl.job.executor.logretentiondays")));
+
+        // start executor
+        try {
+            xxlJobExecutor.start();
+        } catch (Exception e) {
+            logger.error(e.getMessage(), e);
+        }
+    }
+
+    /**
+     * destory
+     */
+    public void destoryXxlJobExecutor() {
+        if (xxlJobExecutor != null) {
+            xxlJobExecutor.destroy();
+        }
+    }
+
+
+    public static Properties loadProperties(String propertyFileName) {
+        InputStreamReader in = null;
+        try {
+            ClassLoader loder = Thread.currentThread().getContextClassLoader();
+
+            in = new InputStreamReader(loder.getResourceAsStream(propertyFileName), "UTF-8");;
+            if (in != null) {
+                Properties prop = new Properties();
+                prop.load(in);
+                return prop;
+            }
+        } catch (IOException e) {
+            logger.error("load {} error!", propertyFileName);
+        } finally {
+            if (in != null) {
+                try {
+                    in.close();
+                } catch (IOException e) {
+                    logger.error("close {} error!", propertyFileName);
+                }
+            }
+        }
+        return null;
+    }
+
+}

+ 32 - 0
xxl-job-executor-samples/xxl-job-executor-sample-frameless/src/main/java/com/xuxueli/executor/sample/frameless/jobhandler/DemoJobHandler.java

@@ -0,0 +1,32 @@
+package com.xuxueli.executor.sample.frameless.jobhandler;
+
+import com.xxl.job.core.biz.model.ReturnT;
+import com.xxl.job.core.handler.IJobHandler;
+import com.xxl.job.core.log.XxlJobLogger;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 任务Handler示例(Bean模式)
+ *
+ * 开发步骤:
+ * 1、继承"IJobHandler":“com.xxl.job.core.handler.IJobHandler”;
+ * 2、注册到执行器工厂:在 "JFinalCoreConfig.initXxlJobExecutor" 中手动注册,注解key值对应的是调度中心新建任务的JobHandler属性的值。
+ * 3、执行日志:需要通过 "XxlJobLogger.log" 打印执行日志;
+ *
+ * @author xuxueli 2015-12-19 19:43:36
+ */
+public class DemoJobHandler extends IJobHandler {
+
+	@Override
+	public ReturnT<String> execute(String param) throws Exception {
+		XxlJobLogger.log("XXL-JOB, Hello World.");
+
+		for (int i = 0; i < 5; i++) {
+			XxlJobLogger.log("beat at:" + i);
+			TimeUnit.SECONDS.sleep(2);
+		}
+		return SUCCESS;
+	}
+
+}

+ 63 - 0
xxl-job-executor-samples/xxl-job-executor-sample-frameless/src/main/java/com/xuxueli/executor/sample/frameless/jobhandler/HttpJobHandler.java

@@ -0,0 +1,63 @@
+package com.xuxueli.executor.sample.frameless.jobhandler;
+
+import com.xxl.job.core.biz.model.ReturnT;
+import com.xxl.job.core.handler.IJobHandler;
+import com.xxl.job.core.log.XxlJobLogger;
+import org.eclipse.jetty.client.HttpClient;
+import org.eclipse.jetty.client.api.ContentResponse;
+import org.eclipse.jetty.client.api.Request;
+import org.eclipse.jetty.http.HttpMethod;
+import org.eclipse.jetty.http.HttpStatus;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 跨平台Http任务
+ *
+ * @author xuxueli 2018-09-16 03:48:34
+ */
+public class HttpJobHandler extends IJobHandler {
+
+	@Override
+	public ReturnT<String> execute(String param) throws Exception {
+
+		// valid
+		if (param==null || param.trim().length()==0) {
+			XxlJobLogger.log("URL Empty");
+			return FAIL;
+		}
+
+		// httpclient
+		HttpClient httpClient = null;
+		try {
+			httpClient = new HttpClient();
+			httpClient.setFollowRedirects(false);	// Configure HttpClient, for example:
+			httpClient.start();						// Start HttpClient
+
+			// request
+			Request request = httpClient.newRequest(param);
+			request.method(HttpMethod.GET);
+			request.timeout(5000, TimeUnit.MILLISECONDS);
+
+			// invoke
+			ContentResponse response = request.send();
+			if (response.getStatus() != HttpStatus.OK_200) {
+				XxlJobLogger.log("Http StatusCode({}) Invalid.", response.getStatus());
+				return FAIL;
+			}
+
+			String responseMsg = response.getContentAsString();
+			XxlJobLogger.log(responseMsg);
+			return SUCCESS;
+		} catch (Exception e) {
+			XxlJobLogger.log(e);
+			return FAIL;
+		} finally {
+			if (httpClient != null) {
+				httpClient.stop();
+			}
+		}
+
+	}
+
+}

+ 34 - 0
xxl-job-executor-samples/xxl-job-executor-sample-frameless/src/main/java/com/xuxueli/executor/sample/frameless/jobhandler/ShardingJobHandler.java

@@ -0,0 +1,34 @@
+package com.xuxueli.executor.sample.frameless.jobhandler;
+
+import com.xxl.job.core.biz.model.ReturnT;
+import com.xxl.job.core.handler.IJobHandler;
+import com.xxl.job.core.log.XxlJobLogger;
+import com.xxl.job.core.util.ShardingUtil;
+
+/**
+ * 分片广播任务
+ *
+ * @author xuxueli 2017-07-25 20:56:50
+ */
+public class ShardingJobHandler extends IJobHandler {
+
+	@Override
+	public ReturnT<String> execute(String param) throws Exception {
+
+		// 分片参数
+		ShardingUtil.ShardingVO shardingVO = ShardingUtil.getShardingVo();
+		XxlJobLogger.log("分片参数:当前分片序号 = {}, 总分片数 = {}", shardingVO.getIndex(), shardingVO.getTotal());
+
+		// 业务逻辑
+		for (int i = 0; i < shardingVO.getTotal(); i++) {
+			if (i == shardingVO.getIndex()) {
+				XxlJobLogger.log("第 {} 片, 命中分片开始处理", i);
+			} else {
+				XxlJobLogger.log("第 {} 片, 忽略", i);
+			}
+		}
+
+		return SUCCESS;
+	}
+	
+}

+ 27 - 0
xxl-job-executor-samples/xxl-job-executor-sample-frameless/src/main/resources/log4j.xml

@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE log4j:configuration PUBLIC "-//log4j/log4j Configuration//EN" "log4j.dtd">
+<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/" threshold="null" debug="null">
+
+	<appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">
+		<param name="Target" value="System.out" />
+		<layout class="org.apache.log4j.PatternLayout">
+            <param name="ConversionPattern" value="%-d{yyyy-MM-dd HH:mm:ss} xxl-job-executor-sample-frameless [%c]-[%t]-[%M]-[%L]-[%p] %m%n"/>
+		</layout>
+	</appender>
+	
+    <appender name="FILE" class="org.apache.log4j.DailyRollingFileAppender">
+        <param name="file" value="/data/applogs/xxl-job/xxl-job-executor-sample-frameless.log"/>
+        <param name="append" value="true"/>
+        <param name="encoding" value="UTF-8"/>
+        <layout class="org.apache.log4j.PatternLayout">
+            <param name="ConversionPattern" value="%-d{yyyy-MM-dd HH:mm:ss} xxl-job-executor-sample-frameless [%c]-[%t]-[%M]-[%L]-[%p] %m%n"/>
+        </layout>
+    </appender>
+
+    <root>
+        <level value="INFO" />
+        <appender-ref ref="CONSOLE" />
+        <appender-ref ref="FILE" />
+    </root>
+
+</log4j:configuration>

+ 15 - 0
xxl-job-executor-samples/xxl-job-executor-sample-frameless/src/main/resources/xxl-job-executor.properties

@@ -0,0 +1,15 @@
+### xxl-job admin address list, such as "http://address" or "http://address01,http://address02"
+xxl.job.admin.addresses=http://127.0.0.1:8080/xxl-job-admin
+
+### xxl-job executor address
+xxl.job.executor.appname=xxl-job-executor-sample
+xxl.job.executor.ip=
+xxl.job.executor.port=9995
+
+### xxl-job, access token
+xxl.job.accessToken=
+
+### xxl-job log path
+xxl.job.executor.logpath=/data/applogs/xxl-job/jobhandler
+### xxl-job log retention days
+xxl.job.executor.logretentiondays=-1

+ 0 - 3
xxl-job-executor-samples/xxl-job-executor-sample-springboot/pom.xml

@@ -16,9 +16,6 @@
     <url>http://www.xuxueli.com/</url>
 
     <properties>
-        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
-        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
-        <java.version>1.7</java.version>
     </properties>
 
     <dependencyManagement>