xueli.xue 8 年之前
父節點
當前提交
d2eafe20cd

+ 7 - 0
xxl-job-core/pom.xml 查看文件

@@ -79,6 +79,13 @@
79 79
 			<version>2.4.5</version>
80 80
 		</dependency>
81 81
 
82
+		<!-- commons-exec -->
83
+		<dependency>
84
+			<groupId>org.apache.commons</groupId>
85
+			<artifactId>commons-exec</artifactId>
86
+			<version>1.3</version>
87
+		</dependency>
88
+
82 89
 	</dependencies>
83 90
 
84 91
 </project>

+ 60 - 0
xxl-job-core/src/main/java/com/xxl/job/core/biz/impl/ExecutorBizImpl.java 查看文件

@@ -11,9 +11,13 @@ import com.xxl.job.core.handler.IJobHandler;
11 11
 import com.xxl.job.core.handler.impl.GlueJobHandler;
12 12
 import com.xxl.job.core.log.XxlJobFileAppender;
13 13
 import com.xxl.job.core.thread.JobThread;
14
+import com.xxl.job.core.util.ScriptUtil;
14 15
 import org.slf4j.Logger;
15 16
 import org.slf4j.LoggerFactory;
16 17
 
18
+import java.io.File;
19
+import java.io.FileOutputStream;
20
+import java.io.IOException;
17 21
 import java.util.Date;
18 22
 
19 23
 /**
@@ -103,7 +107,63 @@ public class ExecutorBizImpl implements ExecutorBiz {
103 107
                 }
104 108
                 jobThread = XxlJobExecutor.registJobThread(triggerParam.getJobId(), new GlueJobHandler(jobHandler, triggerParam.getGlueUpdatetime()));
105 109
             }
110
+        } else if (GlueTypeEnum.GLUE_SHELL==GlueTypeEnum.match(triggerParam.getGlueType())) {
111
+
112
+            // make path
113
+            String scriptPath = XxlJobFileAppender.filePath + "gluesource/";
114
+            String scriptFileName = triggerParam.getJobId() + "_" + triggerParam.getGlueUpdatetime() + ".sh";
115
+
116
+            // valid file
117
+            File scriptFile = new File(scriptPath, scriptFileName);
118
+            if (!scriptFile.exists()) {
119
+                // valid glue source
120
+                if (triggerParam.getGlueSource()==null) {
121
+                    return new ReturnT<String>(ReturnT.FAIL_CODE, "glueSource is null.");
122
+                }
123
+
124
+                // .../gluesource/
125
+                File scriptPathDir = new File(scriptPath);
126
+                if (!scriptPathDir.exists()) {
127
+                    scriptPathDir.mkdirs();
128
+                }
129
+
130
+                // .../gluesource/666-156465656.sh
131
+                scriptFile = new File(scriptPath, scriptFileName);
132
+                FileOutputStream fos = null;
133
+                try {
134
+                    scriptFile.createNewFile();
135
+
136
+                    fos = new FileOutputStream(scriptFile, true);
137
+                    fos.write(triggerParam.getGlueSource().getBytes("utf-8"));
138
+                    fos.flush();
139
+                } catch (IOException e) {
140
+                    logger.error(e.getMessage(), e);
141
+                    return new ReturnT<String>(ReturnT.FAIL_CODE, e.getMessage());
142
+                } finally {
143
+                    if (fos != null) {
144
+                        try {
145
+                            fos.close();
146
+                        } catch (IOException e) {
147
+                            logger.error(e.getMessage(), e);
148
+                        }
149
+                    }
150
+                }
151
+
152
+            }
153
+
154
+            // log File
155
+            String logFileName = XxlJobFileAppender.makeLogFileName(new Date(triggerParam.getLogDateTim()), triggerParam.getLogId());
156
+
157
+            // run script
158
+            ScriptUtil.execToFile("python", scriptFile.getName(), (XxlJobFileAppender.filePath + logFileName) );
159
+
160
+            return ReturnT.FAIL;
161
+        } else if (GlueTypeEnum.GLUE_PYTHON==GlueTypeEnum.match(triggerParam.getGlueType())) {
162
+            String scriptFilePath = XxlJobFileAppender.filePath + "gluesource/" + triggerParam.getJobId() + "_" + triggerParam.getGlueUpdatetime() + ".py";
163
+
106 164
 
165
+        } else {
166
+            return new ReturnT<String>(ReturnT.FAIL_CODE, "glueType[" + triggerParam.getGlueType() + "] is not valid.");
107 167
         }
108 168
 
109 169
         // push data to queue

+ 2 - 0
xxl-job-core/src/main/java/com/xxl/job/core/executor/XxlJobExecutor.java 查看文件

@@ -78,8 +78,10 @@ public class XxlJobExecutor implements ApplicationContextAware, ApplicationListe
78 78
     }
79 79
 
80 80
     // ---------------------------------- init job handler ------------------------------------
81
+    public static ApplicationContext applicationContext;
81 82
 	@Override
82 83
 	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
84
+        XxlJobExecutor.applicationContext = applicationContext;
83 85
 
84 86
         // init job handler action
85 87
         Map<String, Object> serviceBeanMap = applicationContext.getBeansWithAnnotation(JobHander.class);

+ 9 - 18
xxl-job-core/src/main/java/com/xxl/job/core/glue/GlueFactory.java 查看文件

@@ -1,14 +1,12 @@
1 1
 package com.xxl.job.core.glue;
2 2
 
3
+import com.xxl.job.core.executor.XxlJobExecutor;
3 4
 import com.xxl.job.core.handler.IJobHandler;
4 5
 import groovy.lang.GroovyClassLoader;
5 6
 import org.slf4j.Logger;
6 7
 import org.slf4j.LoggerFactory;
7
-import org.springframework.beans.BeansException;
8 8
 import org.springframework.beans.factory.annotation.Autowired;
9 9
 import org.springframework.beans.factory.annotation.Qualifier;
10
-import org.springframework.context.ApplicationContext;
11
-import org.springframework.context.ApplicationContextAware;
12 10
 import org.springframework.core.annotation.AnnotationUtils;
13 11
 
14 12
 import javax.annotation.Resource;
@@ -19,7 +17,7 @@ import java.lang.reflect.Modifier;
19 17
  * glue factory, product class/object by name
20 18
  * @author xuxueli 2016-1-2 20:02:27
21 19
  */
22
-public class GlueFactory implements ApplicationContextAware {
20
+public class GlueFactory {
23 21
 	private static Logger logger = LoggerFactory.getLogger(GlueFactory.class);
24 22
 	
25 23
 	/**
@@ -28,18 +26,11 @@ public class GlueFactory implements ApplicationContextAware {
28 26
 	private GroovyClassLoader groovyClassLoader = new GroovyClassLoader();
29 27
 
30 28
 	// ----------------------------- spring support -----------------------------
31
-	private static ApplicationContext applicationContext;
32
-	private static GlueFactory glueFactory;
29
+	private static GlueFactory glueFactory = new GlueFactory();
33 30
 	public static GlueFactory getInstance(){
34 31
 		return glueFactory;
35 32
 	}
36
-	
37
-	@Override
38
-	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
39
-		GlueFactory.applicationContext = applicationContext;
40
-		GlueFactory.glueFactory = (GlueFactory) applicationContext.getBean("glueFactory");
41
-	}
42
-	
33
+
43 34
 	/**
44 35
 	 * inject action of spring
45 36
 	 * @param instance
@@ -61,21 +52,21 @@ public class GlueFactory implements ApplicationContextAware {
61 52
 				try {
62 53
 					Resource resource = AnnotationUtils.getAnnotation(field, Resource.class);
63 54
 					if (resource.name()!=null && resource.name().length()>0){
64
-						fieldBean = applicationContext.getBean(resource.name());
55
+						fieldBean = XxlJobExecutor.applicationContext.getBean(resource.name());
65 56
 					} else {
66
-						fieldBean = applicationContext.getBean(field.getName());
57
+						fieldBean = XxlJobExecutor.applicationContext.getBean(field.getName());
67 58
 					}
68 59
 				} catch (Exception e) {
69 60
 				}
70 61
 				if (fieldBean==null ) {
71
-					fieldBean = applicationContext.getBean(field.getType());
62
+					fieldBean = XxlJobExecutor.applicationContext.getBean(field.getType());
72 63
 				}
73 64
 			} else if (AnnotationUtils.getAnnotation(field, Autowired.class) != null) {
74 65
 				Qualifier qualifier = AnnotationUtils.getAnnotation(field, Qualifier.class);
75 66
 				if (qualifier!=null && qualifier.value()!=null && qualifier.value().length()>0) {
76
-					fieldBean = applicationContext.getBean(qualifier.value());
67
+					fieldBean = XxlJobExecutor.applicationContext.getBean(qualifier.value());
77 68
 				} else {
78
-					fieldBean = applicationContext.getBean(field.getType());
69
+					fieldBean = XxlJobExecutor.applicationContext.getBean(field.getType());
79 70
 				}
80 71
 			}
81 72
 			

+ 16 - 16
xxl-job-core/src/main/java/com/xxl/job/core/glue/loader/GlueLoader.java 查看文件

@@ -1,16 +1,16 @@
1
-package com.xxl.job.core.glue.loader;
2
-
3
-/**
4
- * code source loader
5
- * @author xuxueli 2016-1-2 20:01:39
6
- */
7
-public interface GlueLoader {
8
-
9
-	/**
10
-	 * load code source by name, ensure every load is the latest.
11
-	 * @param jobId
12
-	 * @return code source
13
-	 */
14
-	public String load(int jobId);
15
-	
16
-}
1
+//package com.xxl.job.core.glue.loader;
2
+//
3
+///**
4
+// * code source loader
5
+// * @author xuxueli 2016-1-2 20:01:39
6
+// */
7
+//public interface GlueLoader {
8
+//
9
+//	/**
10
+//	 * load code source by name, ensure every load is the latest.
11
+//	 * @param jobId
12
+//	 * @return code source
13
+//	 */
14
+//	public String load(int jobId);
15
+//
16
+//}

+ 30 - 30
xxl-job-core/src/main/java/com/xxl/job/core/glue/loader/impl/DbGlueLoader.java 查看文件

@@ -1,30 +1,30 @@
1
-package com.xxl.job.core.glue.loader.impl;
2
-
3
-import com.xxl.job.core.glue.loader.GlueLoader;
4
-import com.xxl.job.core.util.DBUtil;
5
-
6
-import javax.sql.DataSource;
7
-import java.util.List;
8
-import java.util.Map;
9
-
10
-/**
11
- * Created by xuxueli on 16/9/30.
12
- */
13
-public class DbGlueLoader implements GlueLoader {
14
-
15
-    private DataSource dataSource;
16
-    public void setDataSource(DataSource dataSource) {
17
-        this.dataSource = dataSource;
18
-    }
19
-
20
-    @Override
21
-    public String load(int jobId) {
22
-        String sql = "SELECT glue_source FROM XXL_JOB_QRTZ_TRIGGER_INFO WHERE id = ?";
23
-        List<Map<String, Object>> result = DBUtil.query(dataSource, sql, new Object[]{jobId});
24
-        if (result!=null && result.size()==1 && result.get(0)!=null && result.get(0).get("glue_source")!=null ) {
25
-            return (String) result.get(0).get("glue_source");
26
-        }
27
-        return null;
28
-    }
29
-
30
-}
1
+//package com.xxl.job.core.glue.loader.impl;
2
+//
3
+//import com.xxl.job.core.glue.loader.GlueLoader;
4
+//import com.xxl.job.core.util.DBUtil;
5
+//
6
+//import javax.sql.DataSource;
7
+//import java.util.List;
8
+//import java.util.Map;
9
+//
10
+///**
11
+// * Created by xuxueli on 16/9/30.
12
+// */
13
+//public class DbGlueLoader implements GlueLoader {
14
+//
15
+//    private DataSource dataSource;
16
+//    public void setDataSource(DataSource dataSource) {
17
+//        this.dataSource = dataSource;
18
+//    }
19
+//
20
+//    @Override
21
+//    public String load(int jobId) {
22
+//        String sql = "SELECT glue_source FROM XXL_JOB_QRTZ_TRIGGER_INFO WHERE id = ?";
23
+//        List<Map<String, Object>> result = DBUtil.query(dataSource, sql, new Object[]{jobId});
24
+//        if (result!=null && result.size()==1 && result.get(0)!=null && result.get(0).get("glue_source")!=null ) {
25
+//            return (String) result.get(0).get("glue_source");
26
+//        }
27
+//        return null;
28
+//    }
29
+//
30
+//}

+ 86 - 0
xxl-job-core/src/main/java/com/xxl/job/core/util/ScriptUtil.java 查看文件

@@ -0,0 +1,86 @@
1
+package com.xxl.job.core.util;
2
+
3
+import org.apache.commons.exec.CommandLine;
4
+import org.apache.commons.exec.DefaultExecutor;
5
+import org.apache.commons.exec.PumpStreamHandler;
6
+
7
+import java.io.File;
8
+import java.io.FileOutputStream;
9
+
10
+/**
11
+ *  1、内嵌编译器如"PythonInterpreter"无法引用扩展包,因此推荐使用java调用控制台进程方式"Runtime.getRuntime().exec()"来运行脚本(shell或python);
12
+ *  2、因为通过java调用控制台进程方式实现,需要保证目标机器PATH路径正确配置对应编译器;
13
+ *  3、暂时脚本执行日志只能在脚本执行结束后一次性获取,无法保证实时性;因此为确保日志实时性,可改为将脚本打印的日志存储在指定的日志文件上;
14
+ *
15
+ *  知识点:
16
+ *      1、日志输出到日志文件:[>>logfile 2>&1]:将错误输出2以及标准输出1都一起以附加写方式导入logfile文件
17
+ *      2、python 异常输出优先级高于标准输出,体现在Log文件中,因此推荐通过logging方式打日志保持和异常信息一致;否则用prinf日志顺序会错乱
18
+ *
19
+ * Created by xuxueli on 17/2/25.
20
+ */
21
+public class ScriptUtil {
22
+
23
+    private static String pyCmd = "python";
24
+    private static String shllCmd = "bash";
25
+    private static String pyFile = "/Users/xuxueli/workspaces/idea-git-workspace/github/xxl-incubator/xxl-util/src/main/resources/script/pytest.py";
26
+    private static String shellFile = "/Users/xuxueli/workspaces/idea-git-workspace/github/xxl-incubator/xxl-util/src/main/resources/script/shelltest.sh";
27
+    private static String pyLogFile = "/Users/xuxueli/Downloads/tmp/pylog.log";
28
+    private static String shLogFile = "/Users/xuxueli/Downloads/tmp/shlog.log";
29
+
30
+    public static void main(String[] args) {
31
+
32
+        String command = pyCmd;
33
+        String filename = pyFile;
34
+        String logFile = pyLogFile;
35
+        if (false) {
36
+            command = shllCmd;
37
+            filename = shellFile;
38
+            logFile = shLogFile;
39
+        }
40
+
41
+        execToFile(command, filename, logFile);
42
+
43
+    }
44
+
45
+    public static File markScriptFile(){
46
+        return null;
47
+    }
48
+
49
+    /**
50
+     * 日志文件输出方式
51
+     *
52
+     * 优点:支持将目标数据实时输出到指定日志文件中去
53
+     * 缺点:
54
+     *      标准输出和错误输出优先级固定,可能和脚本中顺序不一致
55
+     *      Java无法实时获取
56
+     *
57
+     * @param command
58
+     * @param scriptFile
59
+     * @param logFile
60
+     */
61
+    public static void execToFile(String command, String scriptFile, String logFile){
62
+        try {
63
+            // 标准输出:print (null if watchdog timeout)
64
+            // 错误输出:logging + 异常 (still exists if watchdog timeout)
65
+            // 标准输出
66
+            FileOutputStream fileOutputStream = new FileOutputStream(logFile);
67
+            PumpStreamHandler streamHandler = new PumpStreamHandler(fileOutputStream, fileOutputStream, null);
68
+
69
+            // command
70
+            CommandLine commandline = new CommandLine(command);
71
+            commandline.addArgument(scriptFile);
72
+
73
+            // exec
74
+            DefaultExecutor exec = new DefaultExecutor();
75
+            exec.setExitValues(null);
76
+            exec.setStreamHandler(streamHandler);
77
+            int exitValue = exec.execute(commandline);
78
+        } catch (Exception e) {
79
+            e.printStackTrace();
80
+        }
81
+        /*Process process = Runtime.getRuntime().exec(cmdarray);
82
+        IOUtils.copy(process.getInputStream(), out);
83
+        IOUtils.copy(process.getErrorStream(), out);*/
84
+    }
85
+
86
+}

+ 1 - 6
xxl-job-executor-example/src/main/resources/applicationcontext-xxl-job.xml 查看文件

@@ -38,14 +38,9 @@
38 38
         </property>
39 39
 	</bean>
40 40
 
41
-    <!-- ********************************* "GlueFactory" 配置, 仅在启动 "GLUE模式任务" 时才需要, 否则可删除 ********************************* -->
42
-
43
-	<!-- 配置03、GlueFactory -->
44
-	<bean id="glueFactory" class="com.xxl.job.core.glue.GlueFactory" />
45
-
46 41
     <!-- ********************************* "XXL-JOB公共数据源" 配置, 仅在启动 "DbRegistHelper" 时才需要, 否则可删除 ********************************* -->
47 42
 
48
-	<!-- 配置04、XXL-JOB公共数据源 -->
43
+	<!-- 配置03、XXL-JOB公共数据源 -->
49 44
 	<bean id="xxlJobDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
50 45
 		<property name="driverClass" value="${xxl.job.db.driverClass}" />
51 46
 		<property name="jdbcUrl" value="${xxl.job.db.url}" />