Sfoglia il codice sorgente

Merge pull request #1 from xuxueli/master

update from origin
Mrwb 8 anni fa
parent
commit
3fda544884
52 ha cambiato i file con 740 aggiunte e 433 eliminazioni
  1. 11 0
      .github/ISSUE_TEMPLATE
  2. 14 0
      .github/PULL_REQUEST_TEMPLATE
  3. 61 54
      README.md
  4. 11 0
      doc/XXL-JOB-Englis-Documentation.md
  5. 77 34
      doc/XXL-JOB官方文档.md
  6. 32 1
      pom.xml
  7. 23 26
      xxl-job-admin/pom.xml
  8. 2 1
      xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobApiController.java
  9. 3 1
      xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobInfoController.java
  10. 11 7
      xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobLogController.java
  11. 0 28
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/ExecutorRouter.java
  12. 4 3
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteBusyover.java
  13. 2 1
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteConsistentHash.java
  14. 4 3
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteFailover.java
  15. 2 2
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteFirst.java
  16. 2 1
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteLFU.java
  17. 2 1
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteLRU.java
  18. 2 2
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteLast.java
  19. 2 1
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteRandom.java
  20. 2 1
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteRound.java
  21. 161 73
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/schedule/XxlJobDynamicScheduler.java
  22. 1 1
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobFailMonitorHelper.java
  23. 1 1
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobRegistryMonitorHelper.java
  24. 29 3
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/trigger/XxlJobTrigger.java
  25. 1 0
      xxl-job-admin/src/main/resources/spring/applicationcontext-xxl-job-admin.xml
  26. 5 2
      xxl-job-admin/src/main/resources/xxl-job-admin.properties
  27. 4 3
      xxl-job-admin/src/main/webapp/WEB-INF/template/common/common.macro.ftl
  28. 4 23
      xxl-job-admin/src/main/webapp/WEB-INF/template/help.ftl
  29. 2 2
      xxl-job-admin/src/main/webapp/WEB-INF/template/jobinfo/jobinfo.index.ftl
  30. 7 0
      xxl-job-admin/src/main/webapp/static/js/jobinfo.index.1.js
  31. 32 0
      xxl-job-admin/src/test/java/com/xxl/job/dao/impl/AdminBizTest.java
  32. 10 14
      xxl-job-core/pom.xml
  33. 2 0
      xxl-job-core/src/main/java/com/xxl/job/core/biz/AdminBiz.java
  34. 86 51
      xxl-job-core/src/main/java/com/xxl/job/core/executor/XxlJobExecutor.java
  35. 5 5
      xxl-job-core/src/main/java/com/xxl/job/core/glue/GlueFactory.java
  36. 3 4
      xxl-job-core/src/main/java/com/xxl/job/core/handler/impl/ScriptJobHandler.java
  37. 5 5
      xxl-job-core/src/main/java/com/xxl/job/core/log/XxlJobFileAppender.java
  38. 30 7
      xxl-job-core/src/main/java/com/xxl/job/core/rpc/codec/RpcRequest.java
  39. 6 3
      xxl-job-core/src/main/java/com/xxl/job/core/rpc/netcom/NetComClientProxy.java
  40. 10 2
      xxl-job-core/src/main/java/com/xxl/job/core/rpc/netcom/NetComServerFactory.java
  41. 2 2
      xxl-job-core/src/main/java/com/xxl/job/core/rpc/netcom/jetty/client/JettyClient.java
  42. 17 1
      xxl-job-core/src/main/java/com/xxl/job/core/rpc/netcom/jetty/server/JettyServer.java
  43. 2 9
      xxl-job-core/src/main/java/com/xxl/job/core/thread/ExecutorRegistryThread.java
  44. 2 6
      xxl-job-core/src/main/java/com/xxl/job/core/thread/TriggerCallbackThread.java
  45. 2 2
      xxl-job-core/src/main/java/com/xxl/job/core/util/ScriptUtil.java
  46. 3 21
      xxl-job-executor-example/pom.xml
  47. 2 0
      xxl-job-executor-example/src/main/resources/applicationcontext-xxl-job.xml
  48. 4 1
      xxl-job-executor-example/src/main/resources/xxl-job-executor.properties
  49. 4 1
      xxl-job-executor-example/src/test/java/com/xxl/executor/test/DemoJobHandlerTest.java
  50. 25 24
      xxl-job-executor-springboot-example/pom.xml
  51. 3 0
      xxl-job-executor-springboot-example/src/main/java/com/xxl/job/executor/core/config/XxlJobConfig.java
  52. 3 0
      xxl-job-executor-springboot-example/src/main/resources/application.properties

+ 11 - 0
.github/ISSUE_TEMPLATE

@@ -0,0 +1,11 @@
+Please answer some questions before submitting your issue. Thanks!
+
+### Which version of XXL-JOB do you using?
+
+### Expected behavior
+
+### Actual behavior
+
+### Steps to reproduce the behavior
+
+### Other information

+ 14 - 0
.github/PULL_REQUEST_TEMPLATE

@@ -0,0 +1,14 @@
+**What kind of change does this PR introduce?** (check at least one)
+
+- [ ] Bugfix
+- [ ] Feature
+- [ ] Code style update
+- [ ] Refactor
+- [ ] Build-related changes
+- [ ] Other, please describe:
+
+
+**The description of the PR:**
+
+
+**Other information:**

+ 61 - 54
README.md

@@ -1,21 +1,48 @@
-
-# 分布式任务调度平台XXL-JOB
-
-[![Build Status](https://travis-ci.org/xuxueli/xxl-job.svg?branch=master)](https://travis-ci.org/xuxueli/xxl-job)
-[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.xuxueli/xxl-job/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.xuxueli/xxl-job/)
-[![GitHub release](https://img.shields.io/github/release/xuxueli/xxl-job.svg)](https://github.com/xuxueli/xxl-job/releases)
-[![License](https://img.shields.io/badge/license-GPLv3-blue.svg)](http://www.gnu.org/licenses/gpl-3.0.html)
-[![Gitter](https://badges.gitter.im/xuxueli/xxl-job.svg)](https://gitter.im/xuxueli/xxl-job?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
+<p align="center">
+    <a href="http://www.xuxueli.com/">
+        <img src="https://raw.githubusercontent.com/xuxueli/xxl-job/master/doc/images/xxl-logo.jpg" width="150">
+    </a>
+    <h3 align="center">XXL-JOB</h3>
+    <p align="center">
+        XXL-JOB, a lightweight distributed task scheduling framework.
+        <br>
+        <a href="http://www.xuxueli.com/"><strong>-- Browse xuxueli's website. --</strong></a>
+        <br>
+        <br>
+        <a href="https://travis-ci.org/xuxueli/xxl-job">
+            <img src="https://travis-ci.org/xuxueli/xxl-job.svg?branch=master" >
+        </a>
+        <a href="https://maven-badges.herokuapp.com/maven-central/com.xuxueli/xxl-job/">
+            <img src="https://maven-badges.herokuapp.com/maven-central/com.xuxueli/xxl-job/badge.svg" >
+        </a>
+         <a href="https://github.com/xuxueli/xxl-job/releases">
+             <img src="https://img.shields.io/github/release/xuxueli/xxl-job.svg" >
+         </a>
+         <a href="http://www.gnu.org/licenses/gpl-3.0.html">
+             <img src="https://img.shields.io/badge/license-GPLv3-blue.svg" >
+         </a>
+         <a href="https://gitter.im/xuxueli/xxl-job?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge">
+              <img src="https://badges.gitter.im/xuxueli/xxl-job.svg" >
+          </a>
+    </p>    
+</p>
+
+
+## Intro
+XXL-JOB is a lightweight distributed task scheduling framework. 
+It's core design goal is to develop quickly and learn simple, lightweight, and easy to expand. 
+Now, it's already open source, and many companies use it in production environments, real "out-of-the-box".
 
 XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是开发迅速、学习简单、轻量级、易扩展。现已开放源代码并接入多家公司线上产品线,开箱即用。
 
-![输入图片说明](https://raw.githubusercontent.com/xuxueli/xxl-job/master/doc/images/xxl-logo.jpg "在这里输入图片标题")
 
-### 文档
+## Documentation
+
+- [中文文档](https://github.com/xuxueli/xxl-job/blob/master/doc/XXL-JOB官方文档.md)
+- [Englis Documentation](https://github.com/xuxueli/xxl-job/blob/master/doc/XXL-JOB-Englis-Documentation.md)
 
-- 官方文档:[XXL-JOB官方文档](https://github.com/xuxueli/xxl-job/blob/master/doc/XXL-JOB官方文档.md)
 
-### 特性
+## Features
 - 1、简单:支持通过Web页面对任务进行CRUD操作,操作简单,一分钟上手;
 - 2、动态:支持动态修改任务状态、暂停/恢复任务,以及终止运行中任务,即时生效;
 - 3、调度中心HA(中心式):调度采用中心式设计,“调度中心”基于集群Quartz实现,可保证调度中心HA;
@@ -41,11 +68,8 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是
 - 23、分片广播任务:执行器集群部署时,任务路由策略选择"分片广播"情况下,一次任务调度将会广播触发对应集群中所有执行器执行一次任务,同时传递分片参数;可根据分片参数开发分片任务;
 - 24、动态分片:分片广播任务以执行器为维度进行分片,支持动态扩容执行器集群从而动态增加分片数量,协同进行业务处理;在进行大数据量业务操作时可显著提升任务处理能力和速度。
 
-### 架构图
 
-![输入图片说明](https://static.oschina.net/uploads/img/201707/17190028_aEE2.png "在这里输入图片标题")
-
-### 发展
+## Development
 于2015年中,我在github上创建XXL-JOB项目仓库并提交第一个commit,随之进行系统结构设计,UI选型,交互设计……
 
 于2015-11月,XXL-JOB终于RELEASE了第一个大版本V1.0, 随后我将之发布到OSCHINA,XXL-JOB在OSCHINA上获得了@红薯的热门推荐,同期分别达到了OSCHINA的“热门动弹”排行第一和git.oschina的开源软件月热度排行第一,在此特别感谢红薯,感谢大家的关注和支持。
@@ -56,7 +80,7 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是
 
 于2017-05-13,在上海举办的 "[第62期开源中国源创会](https://www.oschina.net/event/2236961)" 的 "放码过来" 环节,我登台对XXL-JOB做了演讲,台下五百位在场观众反响热烈([图文回顾](https://www.oschina.net/question/2686220_2242120) )。
 
-#### 我司大众点评目前已接入XXL-JOB,内部别名《Ferrari》(Ferrari基于XXL-JOB的V1.1版本定制而成,新接入应用推荐升级最新版本)。
+** 我司大众点评目前已接入XXL-JOB,内部别名《Ferrari》(Ferrari基于XXL-JOB的V1.1版本定制而成,新接入应用推荐升级最新版本)。**
 据最新统计, 自2016-01-21接入至2017-07-07期间,该系统已调度约60万余次,表现优异。新接入应用推荐使用最新版本,因为经过数个大版本的更新,系统的任务模型、UI交互模型以及底层调度通讯模型都有了较大的优化和提升,核心功能更加稳定高效。
 
 至今,XXL-JOB已接入多家公司的线上产品线,接入场景如电商业务,O2O业务和大数据作业等,截止2016-07-19为止,XXL-JOB已接入的公司包括不限于:
@@ -94,60 +118,43 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是
 	- 31、四川互宜达科技有限公司
     - 32、钱包行云(北京)科技有限公司
     - 33、重庆欣才集团
+    - 34、咪咕互动娱乐有限公司(中国移动)
+    - 35、北京诺亦腾科技有限公司
+    - 36、增长引擎(北京)信息技术有限公司
 	- ……
 
 欢迎大家的关注和使用,XXL-JOB也将拥抱变化,持续发展。
 
 
-### 下载
-
-#### 源码仓库地址 (将会在两个git仓库同步发布最新代码)
-
-源码仓库地址 | Release Download
---- | ---
-[https://github.com/xuxueli/xxl-job](https://github.com/xuxueli/xxl-job) | [Download](https://github.com/xuxueli/xxl-job/releases)  
-[http://git.oschina.net/xuxueli0323/xxl-job](http://git.oschina.net/xuxueli0323/xxl-job) | [Download](http://git.oschina.net/xuxueli0323/xxl-job/releases)
-
-
-#### 中央仓库地址 (最新Release版本:1.8.0)
-
-```
-<!-- http://repo1.maven.org/maven2/com/xuxueli/xxl-job-core/ -->
-<dependency>
-    <groupId>com.xuxueli</groupId>
-    <artifactId>xxl-job-core</artifactId>
-    <version>1.8.0</version>
-</dependency>
-```
-
-#### 博客地址 (将会在两个博客同步更新文档)
-
-- [oschina地址](http://my.oschina.net/xuxueli/blog/690978)
-- [cnblogs地址](http://www.cnblogs.com/xuxueli/p/5021979.html)
+## Communication
 
-#### 技术交流群 (仅作技术交流)
+- 腾讯QQ群(6):399758605
+- 腾讯QQ群(5):138274130    (群即将满,请加群6)
+- 腾讯QQ群(4):464762661    (群即将满,请加群6)
+- 腾讯QQ群(3):242151780    (群即将满,请加群6)
+- 腾讯QQ群(2):438249535    (群即将满,请加群6)
+- 腾讯QQ群(1):367260654    (群即将满,请加群6)
+- [Gitter](https://gitter.im/xuxueli/xxl-job)
 
 
-- 群5:138274130      [![image](http://pub.idqqimg.com/wpa/images/group.png)](http://shang.qq.com/wpa/qunwpa?idkey=a3f3aea7e5943e7a24e9726495747ddc19bccd3592d7a70ecb5a97b616062241 )
-- 群4:464762661    (群即将满,请加群5)
-- 群3:242151780    (群即将满,请加群5)
-- 群2:438249535    (群即将满,请加群5)
-- 群1:367260654    (群即将满,请加群5)
+## Issue
+如有问题可在 [Github Issues](https://github.com/xuxueli/xxl-job/issues/) 上提问,也可以加入上文技术交流群;
 
 
-### 报告问题
-XXL-JOB托管在Github上,如有问题可在 [ISSUES](https://github.com/xuxueli/xxl-job/issues/) 上提问,也可以加入上文技术交流群;
+## User Registration
+登记仅为了产品推广,产品开源免费。   
+请接入使用的公司或个人进行用户登记 [登记地址](https://github.com/xuxueli/xxl-job/issues/1 ) 。
 
-### 接入登记(登记仅为了推广,产品开源免费)
-更多接入公司,欢迎在github [登记](https://github.com/xuxueli/xxl-job/issues/1 )
 
-### 开源协议
+## Copyright and license
 产品开源免费,并且将持续提供免费的社区技术支持。个人或企业内部可自由的接入和使用。
 
 XXL-JOB采用GPLv3协议,目的是为了保证用户的自由使用权利。协议可避免专利申请的特殊危险 "the GPL assures that patents cannot be used to render the program non-free.(摘自GPLv3)"。  
+Copyright (c) 2015-present, xuxueli.
 
 ---
-### 支持的话可以扫一扫,支持 [XXL系列](https://github.com/xuxueli) 的建设:)
+## Donate
+支持的话可以扫一扫,请作者喝杯咖啡吧:)
 
 微信:![输入图片说明](https://static.oschina.net/uploads/img/201707/07214300_qhxT.png "在这里输入图片标题")
 支付宝:![输入图片说明](http://images2015.cnblogs.com/blog/554415/201605/554415-20160513183306234-1939652116.png "在这里输入图片标题")

+ 11 - 0
doc/XXL-JOB-Englis-Documentation.md

@@ -0,0 +1,11 @@
+# 《A lightweight distributed task scheduling framework. "XXL-JOB"》
+
+[![Build Status](https://travis-ci.org/xuxueli/xxl-job.svg?branch=master)](https://travis-ci.org/xuxueli/xxl-job)
+[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.xuxueli/xxl-job/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.xuxueli/xxl-job/)
+[![GitHub release](https://img.shields.io/github/release/xuxueli/xxl-job.svg)](https://github.com/xuxueli/xxl-job/releases)
+[![License](https://img.shields.io/badge/license-GPLv3-blue.svg)](http://www.gnu.org/licenses/gpl-3.0.html)
+[![Gitter](https://badges.gitter.im/xuxueli/xxl-job.svg)](https://gitter.im/xuxueli/xxl-job?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
+
+## 1、Intro
+
+### 1.1 overview

+ 77 - 34
doc/XXL-JOB官方文档.md

@@ -86,13 +86,16 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是
 	- 31、四川互宜达科技有限公司
 	- 32、钱包行云(北京)科技有限公司
 	- 33、重庆欣才集团
+    - 34、咪咕互动娱乐有限公司(中国移动)
+    - 35、北京诺亦腾科技有限公司
+    - 36、增长引擎(北京)信息技术有限公司
 	- ……
 
 欢迎大家的关注和使用,XXL-JOB也将拥抱变化,持续发展。
 
 ### 1.4 下载
 
-#### 源码仓库地址 (将会在两个git仓库同步发布最新代码)
+#### 源码仓库地址
 
 源码仓库地址 | Release Download
 --- | ---
@@ -100,35 +103,36 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是
 [http://git.oschina.net/xuxueli0323/xxl-job](http://git.oschina.net/xuxueli0323/xxl-job) | [Download](http://git.oschina.net/xuxueli0323/xxl-job/releases)
 
 
-#### 中央仓库地址 (最新Release版本:1.8.0)
+#### 中央仓库地址
 
 ```
 <!-- http://repo1.maven.org/maven2/com/xuxueli/xxl-job-core/ -->
 <dependency>
     <groupId>com.xuxueli</groupId>
     <artifactId>xxl-job-core</artifactId>
-    <version>1.8.0</version>
+    <version>1.8.1</version>
 </dependency>
 ```
 
-#### 博客地址 (将会在两个博客同步更新文档)
+#### 博客地址
 
 - [oschina地址](http://my.oschina.net/xuxueli/blog/690978)
 - [cnblogs地址](http://www.cnblogs.com/xuxueli/p/5021979.html)
 
-#### 技术交流群 (仅作技术交流)
+#### 技术交流
 
-- 群5:138274130      [![image](http://pub.idqqimg.com/wpa/images/group.png)](http://shang.qq.com/wpa/qunwpa?idkey=a3f3aea7e5943e7a24e9726495747ddc19bccd3592d7a70ecb5a97b616062241 )
-- 群4:464762661    (群即将满,请加群5)
-- 群3:242151780    (群即将满,请加群5)
-- 群2:438249535    (群即将满,请加群5)
-- 群1:367260654    (群即将满,请加群5)
+- 腾讯QQ群(6):399758605
+- 腾讯QQ群(5):138274130    (群即将满,请加群6)
+- 腾讯QQ群(4):464762661    (群即将满,请加群6)
+- 腾讯QQ群(3):242151780    (群即将满,请加群6)
+- 腾讯QQ群(2):438249535    (群即将满,请加群6)
+- 腾讯QQ群(1):367260654    (群即将满,请加群6)
 
 ### 1.5 环境
 - JDK:1.7+
 - Servlet/JSP Spec:3.1/2.3
-- Tomcat:8.5.x/Jetty9.2
-- Spring-boot:1.3.8/Spring4.x
+- Tomcat:8.5.x/Jetty9.2.x
+- Spring-boot:1.5.x/Spring4.x
 - Mysql:5.6+
 - Maven:3+
 
@@ -136,18 +140,18 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是
 ## 二、快速入门
 
 ### 2.1 初始化“调度数据库”
-请下载项目源码并解压,获取 "调度数据库初始化SQL脚本" 并执行即可。正常情况下应该生成16张表,脚本文件位置为:
+请下载项目源码并解压,获取 "调度数据库初始化SQL脚本" 并执行即可,正常情况下应该生成16张表。
 
-    源码解压根目录\xxl-job\db\tables_xxl_job.sql
+"调度数据库初始化SQL脚本" 位置为:
+
+    /xxl-job/db/tables_xxl_job.sql
 
 调度中心支持集群部署,集群情况下各节点务必连接同一个mysql实例;
 
 如果mysql做主从,调度中心集群节点务必强制走主库;
 
 ### 2.2 编译源码
-解压源码,按照maven格式将源码导入IDE, 使用maven进行编译即可,源码结构如下图所示:
-
-![输入图片说明](https://static.oschina.net/uploads/img/201705/11214348_aGgr.png "在这里输入图片标题")
+解压源码,按照maven格式将源码导入IDE, 使用maven进行编译即可,源码结构如下:
 
     xxl-job-admin:调度中心
     xxl-job-core:公共依赖
@@ -160,14 +164,16 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是
     作用:统一管理任务调度平台上调度任务,负责触发调度执行。
 
 #### 步骤一:调度中心配置:
-配置文件以及配置属性如下图所示。
+调度中心配置文件地址:
 
-![输入图片说明](https://static.oschina.net/uploads/img/201705/11214752_Ifvp.png "在这里输入图片标题")
+    /xxl-job/xxl-job-admin/src/main/resources/xxl-job-admin.properties
 
 
+调度中心配置内容说明:
+
     ### 调度中心JDBC链接:链接地址请保持和 2.1章节 所创建的调度数据库的地址一致
     xxl.job.db.driverClass=com.mysql.jdbc.Driver
-    xxl.job.db.url=jdbc:mysql://localhost:3306/xxl-job?useUnicode=true&amp;characterEncoding=UTF-8
+    xxl.job.db.url=jdbc:mysql://localhost:3306/xxl-job?useUnicode=true&characterEncoding=UTF-8
     xxl.job.db.user=root
     xxl.job.db.password=root_pwd
     
@@ -179,9 +185,12 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是
     xxl.job.mail.sendFrom=ovono802302@163.com
     xxl.job.mail.sendNick=《任务调度平台XXL-JOB》
     
-    # 登录账号
+    ### 登录账号
     xxl.job.login.username=admin
     xxl.job.login.password=123456
+    
+    ### 调度中心通讯TOKEN,非空时启用
+    xxl.job.accessToken=
 
 #### 步骤二:部署项目:
 如果已经正确进行上述配置,可将项目编译打war包并部署到tomcat中。
@@ -191,6 +200,13 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是
 
 至此“调度中心”项目已经部署成功。
 
+#### 步骤三:调度中心集群(可选):
+调度中心支持集群部署,提升调度系统可用性。
+
+集群部署唯一要求为:保证每个集群节点配置(db和登陆账号等)保持一致。调度中心通过db配置区分不同集群。
+
+调度中心在集群部署时可通过nginx负载均衡,此时可以为集群分配一个域名。该域名一方面可以用于访问,另一方面也可以用于配置执行器回调地址。
+
 ### 2.4 配置部署“执行器项目”
 
     “执行器”项目:xxl-job-executor-example (如新建执行器项目,可参考该Example执行器项目的配置步骤;)
@@ -200,10 +216,11 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是
 确认pom文件中引入了 "xxl-job-core" 的maven依赖;
     
 #### 步骤二:执行器配置
-配置文件以及配置属性如下图所示。
+执行器配置配置文件地址:
 
-![输入图片说明](https://static.oschina.net/uploads/img/201705/11214800_7G3o.png "在这里输入图片标题")
+    /xxl-job/xxl-job-executor-example/src/main/resources/xxl-job-executor.properties
 
+执行器配置配置内容说明:
 
     ### xxl-job admin address list:调度中心部署跟地址:如调度中心集群部署存在多个地址则用逗号分隔。执行器将会使用该地址进行"执行器心跳注册"和"任务结果回调"。
     xxl.job.admin.addresses=http://127.0.0.1:8080/xxl-job-admin
@@ -215,6 +232,9 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是
     
     ### xxl-job log path:执行器运行日志文件存储的磁盘位置
     xxl.job.executor.logpath=/data/applogs/xxl-job/jobhandler/
+    
+    ### xxl-job, access token:执行器通讯TOKEN,非空时启用
+    xxl.job.accessToken=
 
 
 #### 步骤三:执行器组件配置
@@ -225,7 +245,7 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是
     1、JobHandler 扫描路径:自动扫描容器中JobHandler;
     2、执行器Excutor配置:执行器核心配置;
 
-#### 步骤四:部署项目:
+#### 步骤四:部署执行器项目:
 如果已经正确进行上述配置,可将执行器项目编译打部署,系统提供两个执行器example项目,选择其中一个即可,各自的部署方式如下。
 
     xxl-job-executor-example:项目编译打包成WAR包,并部署到tomcat中。
@@ -233,6 +253,11 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是
 
 至此“执行器”项目已经部署结束。
 
+#### 步骤五:执行器集群(可选):
+执行器支持集群部署,提升调度系统可用性,同时提升任务处理能力。
+
+集群部署唯一要求为:保证集群中每个执行器的配置项 "xxl.job.admin.addresses/调度中心地址" 保持一致,执行器根据该配置进行执行器自动注册等操作。 
+
 
 ### 2.5 开发第一个任务“Hello World”       
 本示例以新建一个 “GLUE模式(Java)” 运行模式的任务为例。更多有关任务的详细配置,请查看“章节三:任务详解”。
@@ -706,6 +731,16 @@ XXL-JOB会为每次调度请求生成一个单独的日志文件,需要通过
 - 1、分片任务场景:10个执行器的集群来处理10w条数据,每台机器只需要处理1w条数据,耗时降低10倍;
 - 2、广播任务场景:广播执行器机器运行shell脚本、广播集群节点进行缓存更新等
 
+#### 5、10 访问令牌(AccessToken)
+为提升系统安全性,调度中心和执行器进行安全性校验,双方AccessToken匹配才允许通讯;
+
+调度中心和执行器,可通过配置项 "xxl.job.accessToken" 进行AccessToken的设置。
+
+调度中心和执行器,如果需要正常通讯,只有两种设置;
+
+- 设置一:调度中心和执行器,均不设置AccessToken;关闭安全性校验;
+- 设置二:调度中心和执行器,设置了相同的AccessToken;
+
 
 ## 六、版本更新日志
 #### 6.1 版本 V1.1.x,新特性[2015-12-05]
@@ -896,41 +931,49 @@ Tips: 历史版本(V1.3.x)目前已经Release至稳定版本, 进入维护阶段
 - 10、执行日志,支持根据运行 "状态" 筛选日志;
 - 11、调度中心任务注册检测逻辑优化;
 
-#### 6.18 版本 V1.8.1 特性[快照版本]
+#### 6.18 版本 V1.8.1 特性[2017-07-30]
 - 1、分片广播任务:执行器集群部署时,任务路由策略选择"分片广播"情况下,一次任务调度将会广播触发集群中所有执行器执行一次任务,可根据分片参数处理分片任务;
 - 2、动态分片:分片广播任务以执行器为维度进行分片,支持动态扩容执行器集群从而动态增加分片数量,协同进行业务处理;在进行大数据量业务操作时可显著提升任务处理能力和速度。
 - 3、执行器JobHandler禁止命名冲突;
 - 4、执行器集群地址列表进行自然排序;
 - 5、调度中心,DAO层代码精简优化并且新增测试用例覆盖;
 - 6、调度中心API服务改为自研RPC形式,统一底层通讯模型;
+- 7、新增调度中心API服务测试Demo,方便在调度中心API扩展和测试;
+- 8、任务列表页交互优化,更换执行器分组时自动刷新任务列表,新建任务时默认定位在当前执行器位置;
+- 9、访问令牌(accessToken):为提升系统安全性,调度中心和执行器进行安全性校验,双方AccessToken匹配才允许通讯;
+- 10、springboot版本执行器,升级至1.5.6.RELEASE版本;
+- 11、统一maven依赖版本管理;
 
 #### TODO LIST
 - 1、任务权限管理:执行器为粒度分配权限,核心操作校验权限;
-- 2、任务分片路由:分片采用一致性Hash算法计算出尽量稳定的分片顺序,即使注册机器存在波动也不会引起分批分片顺序大的波动;
-- 3、失败重试优化:目前失败重试逻辑为,在本次调度请求失败后重新执行一次请求逻辑。优化点为针对调度和执行失败时均做失败重试,重试时重新触发一次完整调度,这将可能导致失败是调度死循环,考虑中。
+- 2、任务分片路由:分片采用一致性Hash算法计算出尽量稳定的分片顺序,即使注册机器存在波动也不会引起分批分片顺序大的波动;目前采用IP自然排序,可以满足需求,待定;
+- 3、失败重试优化:目前失败重试逻辑为,在本次调度请求失败后重新执行一次请求逻辑。优化点为针对调度和执行失败时均做失败重试,重试时重新触发一次完整调度,这将可能导致失败是调度死循环,待定
 - 4、回调失败写文件,查看日志时读文件确认,重启后回调确认;
 - 5、任务依赖,流程图,子任务+会签任务,各节点日志;
 - 6、调度任务优先级;
 - 7、移除quartz依赖,重写调度模块:新增或恢复任务时将下次执行记录插入delayqueue,调度中心集群竞争分布式锁,成功节点批量加载到期delayqueue数据,批量执行。
-- 8、任务执行结果回调失败后重试:待定,防止回调死循环
-- 9、springboot 和 docker镜像,并且推送docker镜像到中央仓库,更进一步实现产品开箱即用;
-- 10、安全校验:调度中心和执行器约定公共密匙,只有密匙一致才允许相互通讯;
+- 8、springboot 和 docker镜像,并且推送docker镜像到中央仓库,更进一步实现产品开箱即用
+- 9、国际化:调度中心界面 + 官方文档,新增英文版本。
+- 10、执行器摘除:执行器销毁时,主动通知调度中心并摘除对应执行器节点,提高执行器状态感知的时效性。
 
 ## 七、其他
 
 #### 7.1 报告问题
 XXL-JOB托管在Github上,如有问题可在 [ISSUES](https://github.com/xuxueli/xxl-job/issues/) 上提问,也可以加入上文技术交流群;
 
-#### 7.2 接入登记(登记仅为了推广,产品开源免费)
-更多接入公司,欢迎在github [登记](https://github.com/xuxueli/xxl-job/issues/1 )
+#### 7.2 用户接入登记
+登记仅为了产品推广,产品开源免费。   
+请接入使用的公司或个人进行用户登记 [登记地址](https://github.com/xuxueli/xxl-job/issues/1 ) 。
 
-#### 7.3 开源协议
+#### 7.3 开源协议和版权
 产品开源免费,并且将持续提供免费的社区技术支持。个人或企业内部可自由的接入和使用。
 
 XXL-JOB采用GPLv3协议,目的是为了保证用户的自由使用权利。协议可避免专利申请的特殊危险 "the GPL assures that patents cannot be used to render the program non-free.(摘自GPLv3)"。  
+Copyright (c) 2015-present, xuxueli.
 
 ---
-#### 支持的话可以扫一扫,支持 [XXL系列](https://github.com/xuxueli) 的建设:)
+#### 捐赠
+支持的话可以扫一扫,请作者喝杯咖啡吧:)
 
 微信:![输入图片说明](https://static.oschina.net/uploads/img/201707/07214300_qhxT.png "在这里输入图片标题")
 支付宝:![输入图片说明](http://images2015.cnblogs.com/blog/554415/201605/554415-20160513183306234-1939652116.png "在这里输入图片标题")

+ 32 - 1
pom.xml

@@ -3,7 +3,7 @@
 	<modelVersion>4.0.0</modelVersion>
 	<groupId>com.xuxueli</groupId>
 	<artifactId>xxl-job</artifactId>
-	<version>1.8.1-SNAPSHOT</version>
+	<version>1.8.2-SNAPSHOT</version>
 	<packaging>pom</packaging>
 
 	<name>${project.artifactId}</name>
@@ -17,6 +17,37 @@
         <module>xxl-job-executor-springboot-example</module>
     </modules>
 
+	<properties>
+		<javax.servlet-api.version>3.0.1</javax.servlet-api.version>
+		<jsp-api.version>2.2</jsp-api.version>
+
+		<spring.version>3.2.18.RELEASE</spring.version>
+		<jackson-mapper-asl.version>1.9.13</jackson-mapper-asl.version>
+		<aspectjweaver.version>1.8.7</aspectjweaver.version>
+		<slf4j-api.version>1.7.25</slf4j-api.version>
+		<freemarker.version>2.3.20</freemarker.version>
+		<junit.version>4.11</junit.version>
+
+		<jetty-server.version>9.2.22.v20170606</jetty-server.version>
+		<hessian.version>4.0.38</hessian.version>
+		<httpclient.version>4.3.6</httpclient.version>
+
+		<commons-exec.version>1.3</commons-exec.version>
+		<commons-beanutils.version>1.9.2</commons-beanutils.version>
+		<commons-lang.version>2.6</commons-lang.version>
+
+		<c3p0.version>0.9.5.2</c3p0.version>
+		<mysql-connector-java.version>5.1.29</mysql-connector-java.version>
+		<mybatis-spring.version>1.2.2</mybatis-spring.version>
+		<mybatis.version>3.2.8</mybatis.version>
+
+		<groovy-all.version>2.4.5</groovy-all.version>
+		<mail.version>1.4.6</mail.version>
+		<quartz.version>2.3.0</quartz.version>
+
+		<spring-boot.version>1.5.6.RELEASE</spring-boot.version>
+	</properties>
+
 	<build>
 		<plugins>
 			<plugin>

+ 23 - 26
xxl-job-admin/pom.xml

@@ -4,15 +4,11 @@
 	<parent>
 		<groupId>com.xuxueli</groupId>
 		<artifactId>xxl-job</artifactId>
-		<version>1.8.1-SNAPSHOT</version>
+		<version>1.8.2-SNAPSHOT</version>
 	</parent>
 	<artifactId>xxl-job-admin</artifactId>
 	<packaging>war</packaging>
 
-	<properties>
-		<spring.version>3.2.17.RELEASE</spring.version>
-	</properties>
-
 	<dependencies>
 		<!-- springframe start -->
 		<dependency>
@@ -40,59 +36,59 @@
 		<dependency>
 			<groupId>org.aspectj</groupId>
 			<artifactId>aspectjweaver</artifactId>
-			<version>1.8.7</version>
+			<version>${aspectjweaver.version}</version>
 		</dependency>
 		<!-- jackson (support spring json) -->
 		<dependency>
 			<groupId>org.codehaus.jackson</groupId>
 			<artifactId>jackson-mapper-asl</artifactId>
-			<version>1.9.13</version>
+			<version>${jackson-mapper-asl.version}</version>
 		</dependency>
 
 		<!-- slf4j -->
 		<dependency>
 			<groupId>org.slf4j</groupId>
 			<artifactId>slf4j-log4j12</artifactId>
-			<version>1.7.21</version>
+			<version>${slf4j-api.version}</version>
 		</dependency>
 
 		<!-- freemarker -->
 		<dependency>
 			<groupId>org.freemarker</groupId>
 			<artifactId>freemarker</artifactId>
-			<version>2.3.20</version>
+			<version>${freemarker.version}</version>
 		</dependency>
 
 		<!-- commons-beanutils -->
 		<dependency>
 			<groupId>commons-beanutils</groupId>
 			<artifactId>commons-beanutils</artifactId>
-			<version>1.9.2</version>
+			<version>${commons-beanutils.version}</version>
 		</dependency>
 		<!-- commons-lang -->
 		<dependency>
 			<groupId>commons-lang</groupId>
 			<artifactId>commons-lang</artifactId>
-			<version>2.6</version>
+			<version>${commons-lang.version}</version>
 		</dependency>
 
 		<!-- servlet -->
 		<dependency>
 			<groupId>javax.servlet</groupId>
 			<artifactId>javax.servlet-api</artifactId>
-			<version>3.0.1</version>
+			<version>${javax.servlet-api.version}</version>
 		</dependency>
 		<dependency>
 			<groupId>javax.servlet.jsp</groupId>
 			<artifactId>jsp-api</artifactId>
-			<version>2.2</version>
+			<version>${jsp-api.version}</version>
 		</dependency>
 
 		<!-- junit -->
 		<dependency>
 			<groupId>junit</groupId>
 			<artifactId>junit</artifactId>
-			<version>4.11</version>
+			<version>${junit.version}</version>
 			<scope>test</scope>
 		</dependency>
 
@@ -100,45 +96,46 @@
 		<dependency>
 			<groupId>com.mchange</groupId>
 			<artifactId>c3p0</artifactId>
-			<version>0.9.5.2</version>
+			<version>${c3p0.version}</version>
+		</dependency>
+		<!-- mysql-connector -->
+		<dependency>
+			<groupId>mysql</groupId>
+			<artifactId>mysql-connector-java</artifactId>
+			<version>${mysql-connector-java.version}</version>
 		</dependency>
 		<!-- mybatis-spring -->
 		<dependency>
 			<groupId>org.mybatis</groupId>
 			<artifactId>mybatis-spring</artifactId>
-			<version>1.2.2</version>
+			<version>${mybatis-spring.version}</version>
 		</dependency>
 		<dependency>
 			<groupId>org.mybatis</groupId>
 			<artifactId>mybatis</artifactId>
-			<version>3.2.8</version>
-		</dependency>
-		<!-- mysql-connector -->
-		<dependency>
-			<groupId>mysql</groupId>
-			<artifactId>mysql-connector-java</artifactId>
-			<version>5.1.29</version>
+			<version>${mybatis.version}</version>
 		</dependency>
 
+
 		<!-- httpclient -->
 		<dependency>
 			<groupId>org.apache.httpcomponents</groupId>
 			<artifactId>httpclient</artifactId>
-			<version>4.3.6</version>
+			<version>${httpclient.version}</version>
 		</dependency>
 
 		<!-- javax.mail -->
 		<dependency>
 			<groupId>javax.mail</groupId>
 			<artifactId>mail</artifactId>
-			<version>1.4.6</version>
+			<version>${mail.version}</version>
 		</dependency>
 
 		<!-- quartz :quartz-2.2.3/c3p0-0.9.1.1/slf4j-api-1.6.6 -->
 		<dependency>
 			<groupId>org.quartz-scheduler</groupId>
 			<artifactId>quartz</artifactId>
-			<version>2.3.0</version>
+			<version>${quartz.version}</version>
 		</dependency>
 
 		<!-- xxl-job-core -->

+ 2 - 1
xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobApiController.java

@@ -1,6 +1,7 @@
 package com.xxl.job.admin.controller;
 
 import com.xxl.job.admin.controller.annotation.PermessionLimit;
+import com.xxl.job.core.biz.AdminBiz;
 import com.xxl.job.core.rpc.codec.RpcRequest;
 import com.xxl.job.core.rpc.codec.RpcResponse;
 import com.xxl.job.core.rpc.netcom.NetComServerFactory;
@@ -46,7 +47,7 @@ public class JobApiController {
         }
     }
 
-    @RequestMapping("/api")
+    @RequestMapping(AdminBiz.MAPPING)
     @PermessionLimit(limit=false)
     public void api(HttpServletRequest request, HttpServletResponse response) throws IOException {
 

+ 3 - 1
xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobInfoController.java

@@ -33,7 +33,7 @@ public class JobInfoController {
 	private XxlJobService xxlJobService;
 	
 	@RequestMapping
-	public String index(Model model) {
+	public String index(Model model, @RequestParam(required = false, defaultValue = "-1") int jobGroup) {
 
 		// 枚举-字典
 		model.addAttribute("ExecutorRouteStrategyEnum", ExecutorRouteStrategyEnum.values());	// 路由策略-列表
@@ -44,6 +44,8 @@ public class JobInfoController {
 		// 任务组
 		List<XxlJobGroup> jobGroupList =  xxlJobGroupDao.findAll();
 		model.addAttribute("JobGroupList", jobGroupList);
+		model.addAttribute("jobGroup", jobGroup);
+
 		return "jobinfo/jobinfo.index";
 	}
 	

+ 11 - 7
xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobLogController.java

@@ -3,6 +3,7 @@ package com.xxl.job.admin.controller;
 import com.xxl.job.admin.core.model.XxlJobGroup;
 import com.xxl.job.admin.core.model.XxlJobInfo;
 import com.xxl.job.admin.core.model.XxlJobLog;
+import com.xxl.job.admin.core.schedule.XxlJobDynamicScheduler;
 import com.xxl.job.admin.dao.XxlJobGroupDao;
 import com.xxl.job.admin.dao.XxlJobInfoDao;
 import com.xxl.job.admin.dao.XxlJobLogDao;
@@ -12,6 +13,8 @@ import com.xxl.job.core.biz.model.ReturnT;
 import com.xxl.job.core.rpc.netcom.NetComClientProxy;
 import org.apache.commons.lang.StringUtils;
 import org.apache.commons.lang.time.DateUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Controller;
 import org.springframework.ui.Model;
 import org.springframework.web.bind.annotation.RequestMapping;
@@ -32,6 +35,7 @@ import java.util.Map;
 @Controller
 @RequestMapping("/joblog")
 public class JobLogController {
+	private static Logger logger = LoggerFactory.getLogger(JobLogController.class);
 
 	@Resource
 	private XxlJobGroupDao xxlJobGroupDao;
@@ -116,7 +120,7 @@ public class JobLogController {
 	@ResponseBody
 	public ReturnT<LogResult> logDetailCat(String executorAddress, long triggerTime, int logId, int fromLineNum){
 		try {
-			ExecutorBiz executorBiz = (ExecutorBiz) new NetComClientProxy(ExecutorBiz.class, executorAddress).getObject();
+			ExecutorBiz executorBiz = XxlJobDynamicScheduler.getExecutorBiz(executorAddress);
 			ReturnT<LogResult> logResult = executorBiz.log(triggerTime, logId, fromLineNum);
 
 			// is end
@@ -129,7 +133,7 @@ public class JobLogController {
 
 			return logResult;
 		} catch (Exception e) {
-			e.printStackTrace();
+			logger.error(e.getMessage(), e);
 			return new ReturnT<LogResult>(ReturnT.FAIL_CODE, e.getMessage());
 		}
 	}
@@ -148,14 +152,14 @@ public class JobLogController {
 		}
 
 		// request of kill
-		ExecutorBiz executorBiz = null;
+		ReturnT<String> runResult = null;
 		try {
-			executorBiz = (ExecutorBiz) new NetComClientProxy(ExecutorBiz.class, log.getExecutorAddress()).getObject();
+			ExecutorBiz executorBiz = XxlJobDynamicScheduler.getExecutorBiz(log.getExecutorAddress());
+			runResult = executorBiz.kill(jobInfo.getId());
 		} catch (Exception e) {
-			e.printStackTrace();
-			return new ReturnT<String>(500, e.getMessage());
+			logger.error(e.getMessage(), e);
+			runResult = new ReturnT<String>(500, e.getMessage());
 		}
-		ReturnT<String> runResult = executorBiz.kill(jobInfo.getId());
 
 		if (ReturnT.SUCCESS_CODE == runResult.getCode()) {
 			log.setHandleCode(ReturnT.FAIL_CODE);

+ 0 - 28
xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/ExecutorRouter.java

@@ -1,9 +1,7 @@
 package com.xxl.job.admin.core.route;
 
-import com.xxl.job.core.biz.ExecutorBiz;
 import com.xxl.job.core.biz.model.ReturnT;
 import com.xxl.job.core.biz.model.TriggerParam;
-import com.xxl.job.core.rpc.netcom.NetComClientProxy;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -24,30 +22,4 @@ public abstract class ExecutorRouter {
      */
     public abstract ReturnT<String> routeRun(TriggerParam triggerParam, ArrayList<String> addressList);
 
-    /**
-     * run executor
-     * @param triggerParam
-     * @param address
-     * @return  ReturnT.content: final address
-     */
-    public static ReturnT<String> runExecutor(TriggerParam triggerParam, String address){
-        ReturnT<String> runResult = null;
-        try {
-            ExecutorBiz executorBiz = (ExecutorBiz) new NetComClientProxy(ExecutorBiz.class, address).getObject();
-            runResult = executorBiz.run(triggerParam);
-        } catch (Exception e) {
-            logger.error("", e);
-            runResult = new ReturnT<String>(ReturnT.FAIL_CODE, ""+e );
-        }
-
-        StringBuffer runResultSB = new StringBuffer("触发调度:");
-        runResultSB.append("<br>address:").append(address);
-        runResultSB.append("<br>code:").append(runResult.getCode());
-        runResultSB.append("<br>msg:").append(runResult.getMsg());
-
-        runResult.setMsg(runResultSB.toString());
-        runResult.setContent(address);
-        return runResult;
-    }
-
 }

+ 4 - 3
xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteBusyover.java

@@ -1,10 +1,11 @@
 package com.xxl.job.admin.core.route.strategy;
 
 import com.xxl.job.admin.core.route.ExecutorRouter;
+import com.xxl.job.admin.core.schedule.XxlJobDynamicScheduler;
+import com.xxl.job.admin.core.trigger.XxlJobTrigger;
 import com.xxl.job.core.biz.ExecutorBiz;
 import com.xxl.job.core.biz.model.ReturnT;
 import com.xxl.job.core.biz.model.TriggerParam;
-import com.xxl.job.core.rpc.netcom.NetComClientProxy;
 
 import java.util.ArrayList;
 
@@ -25,7 +26,7 @@ public class ExecutorRouteBusyover extends ExecutorRouter {
             // beat
             ReturnT<String> idleBeatResult = null;
             try {
-                ExecutorBiz executorBiz = (ExecutorBiz) new NetComClientProxy(ExecutorBiz.class, address).getObject();
+                ExecutorBiz executorBiz = XxlJobDynamicScheduler.getExecutorBiz(address);
                 idleBeatResult = executorBiz.idleBeat(triggerParam.getJobId());
             } catch (Exception e) {
                 logger.error(e.getMessage(), e);
@@ -40,7 +41,7 @@ public class ExecutorRouteBusyover extends ExecutorRouter {
             // beat success
             if (idleBeatResult.getCode() == ReturnT.SUCCESS_CODE) {
 
-                ReturnT<String> runResult = runExecutor(triggerParam, address);
+                ReturnT<String> runResult = XxlJobTrigger.runExecutor(triggerParam, address);
                 idleBeatResultSB.append("<br><br>").append(runResult.getMsg());
 
                 // result

+ 2 - 1
xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteConsistentHash.java

@@ -1,6 +1,7 @@
 package com.xxl.job.admin.core.route.strategy;
 
 import com.xxl.job.admin.core.route.ExecutorRouter;
+import com.xxl.job.admin.core.trigger.XxlJobTrigger;
 import com.xxl.job.core.biz.model.ReturnT;
 import com.xxl.job.core.biz.model.TriggerParam;
 
@@ -82,7 +83,7 @@ public class ExecutorRouteConsistentHash extends ExecutorRouter {
         String address = route(triggerParam.getJobId(), addressList);
 
         // run executor
-        ReturnT<String> runResult = runExecutor(triggerParam, address);
+        ReturnT<String> runResult = XxlJobTrigger.runExecutor(triggerParam, address);
         runResult.setContent(address);
         return runResult;
     }

+ 4 - 3
xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteFailover.java

@@ -1,10 +1,11 @@
 package com.xxl.job.admin.core.route.strategy;
 
 import com.xxl.job.admin.core.route.ExecutorRouter;
+import com.xxl.job.admin.core.schedule.XxlJobDynamicScheduler;
+import com.xxl.job.admin.core.trigger.XxlJobTrigger;
 import com.xxl.job.core.biz.ExecutorBiz;
 import com.xxl.job.core.biz.model.ReturnT;
 import com.xxl.job.core.biz.model.TriggerParam;
-import com.xxl.job.core.rpc.netcom.NetComClientProxy;
 
 import java.util.ArrayList;
 
@@ -25,7 +26,7 @@ public class ExecutorRouteFailover extends ExecutorRouter {
             // beat
             ReturnT<String> beatResult = null;
             try {
-                ExecutorBiz executorBiz = (ExecutorBiz) new NetComClientProxy(ExecutorBiz.class, address).getObject();
+                ExecutorBiz executorBiz = XxlJobDynamicScheduler.getExecutorBiz(address);
                 beatResult = executorBiz.beat();
             } catch (Exception e) {
                 logger.error(e.getMessage(), e);
@@ -40,7 +41,7 @@ public class ExecutorRouteFailover extends ExecutorRouter {
             // beat success
             if (beatResult.getCode() == ReturnT.SUCCESS_CODE) {
 
-                ReturnT<String> runResult = runExecutor(triggerParam, address);
+                ReturnT<String> runResult = XxlJobTrigger.runExecutor(triggerParam, address);
                 beatResultSB.append("<br><br>").append(runResult.getMsg());
 
                 // result

+ 2 - 2
xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteFirst.java

@@ -1,7 +1,7 @@
 package com.xxl.job.admin.core.route.strategy;
 
-import com.xxl.job.admin.core.model.XxlJobLog;
 import com.xxl.job.admin.core.route.ExecutorRouter;
+import com.xxl.job.admin.core.trigger.XxlJobTrigger;
 import com.xxl.job.core.biz.model.ReturnT;
 import com.xxl.job.core.biz.model.TriggerParam;
 
@@ -23,7 +23,7 @@ public class ExecutorRouteFirst extends ExecutorRouter {
         String address = route(triggerParam.getJobId(), addressList);
 
         // run executor
-        ReturnT<String> runResult = runExecutor(triggerParam, address);
+        ReturnT<String> runResult = XxlJobTrigger.runExecutor(triggerParam, address);
         runResult.setContent(address);
         return runResult;
     }

+ 2 - 1
xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteLFU.java

@@ -1,6 +1,7 @@
 package com.xxl.job.admin.core.route.strategy;
 
 import com.xxl.job.admin.core.route.ExecutorRouter;
+import com.xxl.job.admin.core.trigger.XxlJobTrigger;
 import com.xxl.job.core.biz.model.ReturnT;
 import com.xxl.job.core.biz.model.TriggerParam;
 
@@ -62,7 +63,7 @@ public class ExecutorRouteLFU extends ExecutorRouter {
         String address = route(triggerParam.getJobId(), addressList);
 
         // run executor
-        ReturnT<String> runResult = runExecutor(triggerParam, address);
+        ReturnT<String> runResult = XxlJobTrigger.runExecutor(triggerParam, address);
         runResult.setContent(address);
         return runResult;
     }

+ 2 - 1
xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteLRU.java

@@ -1,6 +1,7 @@
 package com.xxl.job.admin.core.route.strategy;
 
 import com.xxl.job.admin.core.route.ExecutorRouter;
+import com.xxl.job.admin.core.trigger.XxlJobTrigger;
 import com.xxl.job.core.biz.model.ReturnT;
 import com.xxl.job.core.biz.model.TriggerParam;
 
@@ -61,7 +62,7 @@ public class ExecutorRouteLRU extends ExecutorRouter {
         String address = route(triggerParam.getJobId(), addressList);
 
         // run executor
-        ReturnT<String> runResult = runExecutor(triggerParam, address);
+        ReturnT<String> runResult = XxlJobTrigger.runExecutor(triggerParam, address);
         runResult.setContent(address);
         return runResult;
     }

+ 2 - 2
xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteLast.java

@@ -1,7 +1,7 @@
 package com.xxl.job.admin.core.route.strategy;
 
-import com.xxl.job.admin.core.model.XxlJobLog;
 import com.xxl.job.admin.core.route.ExecutorRouter;
+import com.xxl.job.admin.core.trigger.XxlJobTrigger;
 import com.xxl.job.core.biz.model.ReturnT;
 import com.xxl.job.core.biz.model.TriggerParam;
 
@@ -22,7 +22,7 @@ public class ExecutorRouteLast extends ExecutorRouter {
         String address = route(triggerParam.getJobId(), addressList);
 
         // run executor
-        ReturnT<String> runResult = runExecutor(triggerParam, address);
+        ReturnT<String> runResult = XxlJobTrigger.runExecutor(triggerParam, address);
         runResult.setContent(address);
         return runResult;
     }

+ 2 - 1
xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteRandom.java

@@ -1,6 +1,7 @@
 package com.xxl.job.admin.core.route.strategy;
 
 import com.xxl.job.admin.core.route.ExecutorRouter;
+import com.xxl.job.admin.core.trigger.XxlJobTrigger;
 import com.xxl.job.core.biz.model.ReturnT;
 import com.xxl.job.core.biz.model.TriggerParam;
 
@@ -25,7 +26,7 @@ public class ExecutorRouteRandom extends ExecutorRouter {
         String address = route(triggerParam.getJobId(), addressList);
 
         // run executor
-        ReturnT<String> runResult = runExecutor(triggerParam, address);
+        ReturnT<String> runResult = XxlJobTrigger.runExecutor(triggerParam, address);
         runResult.setContent(address);
         return runResult;
     }

+ 2 - 1
xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteRound.java

@@ -1,6 +1,7 @@
 package com.xxl.job.admin.core.route.strategy;
 
 import com.xxl.job.admin.core.route.ExecutorRouter;
+import com.xxl.job.admin.core.trigger.XxlJobTrigger;
 import com.xxl.job.core.biz.model.ReturnT;
 import com.xxl.job.core.biz.model.TriggerParam;
 
@@ -41,7 +42,7 @@ public class ExecutorRouteRound extends ExecutorRouter {
         String address = route(triggerParam.getJobId(), addressList);
 
         // run executor
-        ReturnT<String> runResult = runExecutor(triggerParam, address);
+        ReturnT<String> runResult = XxlJobTrigger.runExecutor(triggerParam, address);
         runResult.setContent(address);
         return runResult;
     }

+ 161 - 73
xxl-job-admin/src/main/java/com/xxl/job/admin/core/schedule/XxlJobDynamicScheduler.java

@@ -9,62 +9,52 @@ import com.xxl.job.admin.dao.XxlJobInfoDao;
 import com.xxl.job.admin.dao.XxlJobLogDao;
 import com.xxl.job.admin.dao.XxlJobRegistryDao;
 import com.xxl.job.core.biz.AdminBiz;
+import com.xxl.job.core.biz.ExecutorBiz;
+import com.xxl.job.core.rpc.netcom.NetComClientProxy;
 import com.xxl.job.core.rpc.netcom.NetComServerFactory;
 import org.quartz.*;
 import org.quartz.Trigger.TriggerState;
-import org.quartz.impl.matchers.GroupMatcher;
 import org.quartz.impl.triggers.CronTriggerImpl;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.BeansException;
-import org.springframework.beans.factory.InitializingBean;
 import org.springframework.context.ApplicationContext;
 import org.springframework.context.ApplicationContextAware;
 import org.springframework.util.Assert;
 
-import java.util.*;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.concurrent.ConcurrentHashMap;
 
 /**
  * base quartz scheduler util
  * @author xuxueli 2015-12-19 16:13:53
  */
-public final class XxlJobDynamicScheduler implements ApplicationContextAware, InitializingBean {
+public final class XxlJobDynamicScheduler implements ApplicationContextAware {
     private static final Logger logger = LoggerFactory.getLogger(XxlJobDynamicScheduler.class);
-    
-    // Scheduler
+
+    // ---------------------- param ----------------------
+
+    // scheduler
     private static Scheduler scheduler;
     public void setScheduler(Scheduler scheduler) {
 		XxlJobDynamicScheduler.scheduler = scheduler;
 	}
-    
-    // init
-    public void init() throws Exception {
-		// admin registry monitor run
-        JobRegistryMonitorHelper.getInstance().start();
 
-        // admin monitor run
-        JobFailMonitorHelper.getInstance().start();
-
-        // rpc-service, base on spring-mvc
-        NetComServerFactory.putService(AdminBiz.class, XxlJobDynamicScheduler.adminBiz);
+	// accessToken
+    private static String accessToken;
+    public void setAccessToken(String accessToken) {
+        this.accessToken = accessToken;
     }
-    
-    // destroy
-    public void destroy(){
-        // admin registry stop
-        JobRegistryMonitorHelper.getInstance().toStop();
 
-        // admin monitor stop
-        JobFailMonitorHelper.getInstance().toStop();
-    }
-    
-    // xxlJobLogDao、xxlJobInfoDao
+    // dao
     public static XxlJobLogDao xxlJobLogDao;
     public static XxlJobInfoDao xxlJobInfoDao;
     public static XxlJobRegistryDao xxlJobRegistryDao;
     public static XxlJobGroupDao xxlJobGroupDao;
     public static AdminBiz adminBiz;
 
+    // ---------------------- applicationContext ----------------------
     @Override
 	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
 		XxlJobDynamicScheduler.xxlJobLogDao = applicationContext.getBean(XxlJobLogDao.class);
@@ -73,48 +63,60 @@ public final class XxlJobDynamicScheduler implements ApplicationContextAware, In
         XxlJobDynamicScheduler.xxlJobGroupDao = applicationContext.getBean(XxlJobGroupDao.class);
         XxlJobDynamicScheduler.adminBiz = applicationContext.getBean(AdminBiz.class);
 	}
-    
-	@Override
-    public void afterPropertiesSet() throws Exception {
+
+    // ---------------------- init + destroy ----------------------
+    public void init() throws Exception {
+        // admin registry monitor run
+        JobRegistryMonitorHelper.getInstance().start();
+
+        // admin monitor run
+        JobFailMonitorHelper.getInstance().start();
+
+        // admin-server(spring-mvc)
+        NetComServerFactory.putService(AdminBiz.class, XxlJobDynamicScheduler.adminBiz);
+        NetComServerFactory.setAccessToken(accessToken);
+
+        // valid
         Assert.notNull(scheduler, "quartz scheduler is null");
         logger.info(">>>>>>>>> init quartz scheduler success.[{}]", scheduler);
-       
     }
-	
-	// getJobKeys
-	@Deprecated
-	public static List<Map<String, Object>> getJobList(){
-		List<Map<String, Object>> jobList = new ArrayList<Map<String,Object>>();
-		
-		try {
-			if (scheduler.getJobGroupNames()==null || scheduler.getJobGroupNames().size()==0) {
-				return null;
-			}
-			String groupName = scheduler.getJobGroupNames().get(0);
-			Set<JobKey> jobKeys = scheduler.getJobKeys(GroupMatcher.jobGroupEquals(groupName));
-			if (jobKeys!=null && jobKeys.size()>0) {
-				for (JobKey jobKey : jobKeys) {
-			        TriggerKey triggerKey = TriggerKey.triggerKey(jobKey.getName(), Scheduler.DEFAULT_GROUP);
-			        Trigger trigger = scheduler.getTrigger(triggerKey);
-			        JobDetail jobDetail = scheduler.getJobDetail(jobKey);
-			        TriggerState triggerState = scheduler.getTriggerState(triggerKey);
-			        Map<String, Object> jobMap = new HashMap<String, Object>();
-			        jobMap.put("TriggerKey", triggerKey);
-			        jobMap.put("Trigger", trigger);
-			        jobMap.put("JobDetail", jobDetail);
-			        jobMap.put("TriggerState", triggerState);
-			        jobList.add(jobMap);
-				}
-			}
-			
-		} catch (SchedulerException e) {
-			e.printStackTrace();
-			return null;
-		}
-		return jobList;
-	}
-	
-	// fill job info
+
+    public void destroy(){
+        // admin registry stop
+        JobRegistryMonitorHelper.getInstance().toStop();
+
+        // admin monitor stop
+        JobFailMonitorHelper.getInstance().toStop();
+    }
+
+    // ---------------------- executor-client ----------------------
+    private static ConcurrentHashMap<String, ExecutorBiz> executorBizRepository = new ConcurrentHashMap<String, ExecutorBiz>();
+    public static ExecutorBiz getExecutorBiz(String address) throws Exception {
+        // valid
+        if (address==null || address.trim().length()==0) {
+            return null;
+        }
+
+        // load-cache
+        address = address.trim();
+        ExecutorBiz executorBiz = executorBizRepository.get(address);
+        if (executorBiz != null) {
+            return executorBiz;
+        }
+
+        // set-cache
+        executorBiz = (ExecutorBiz) new NetComClientProxy(ExecutorBiz.class, address, accessToken).getObject();
+        executorBizRepository.put(address, executorBiz);
+        return executorBiz;
+    }
+
+    // ---------------------- schedule util ----------------------
+
+    /**
+     * fill job info
+     *
+     * @param jobInfo
+     */
 	public static void fillJobInfo(XxlJobInfo jobInfo) {
 		// TriggerKey : name + group
         String group = String.valueOf(jobInfo.getJobGroup());
@@ -145,14 +147,28 @@ public final class XxlJobDynamicScheduler implements ApplicationContextAware, In
 		}
 	}
 	
-	// check if exists
+    /**
+     * check if exists
+     *
+     * @param jobName
+     * @param jobGroup
+     * @return
+     * @throws SchedulerException
+     */
 	public static boolean checkExists(String jobName, String jobGroup) throws SchedulerException{
 		TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);
 		return scheduler.checkExists(triggerKey);
 	}
 
-	// addJob 新增
-	@SuppressWarnings("unchecked")
+    /**
+     * addJob
+     *
+     * @param jobName
+     * @param jobGroup
+     * @param cronExpression
+     * @return
+     * @throws SchedulerException
+     */
 	public static boolean addJob(String jobName, String jobGroup, String cronExpression) throws SchedulerException {
     	// TriggerKey : name + group
         TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);
@@ -185,7 +201,15 @@ public final class XxlJobDynamicScheduler implements ApplicationContextAware, In
         return true;
     }
     
-    // reschedule
+    /**
+     * rescheduleJob
+     *
+     * @param jobGroup
+     * @param jobName
+     * @param cronExpression
+     * @return
+     * @throws SchedulerException
+     */
 	public static boolean rescheduleJob(String jobGroup, String jobName, String cronExpression) throws SchedulerException {
     	
     	// TriggerKey valid if_exists
@@ -234,7 +258,14 @@ public final class XxlJobDynamicScheduler implements ApplicationContextAware, In
         return true;
     }
     
-    // unscheduleJob
+    /**
+     * unscheduleJob
+     *
+     * @param jobName
+     * @param jobGroup
+     * @return
+     * @throws SchedulerException
+     */
     public static boolean removeJob(String jobName, String jobGroup) throws SchedulerException {
     	// TriggerKey : name + group
         TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);
@@ -246,7 +277,14 @@ public final class XxlJobDynamicScheduler implements ApplicationContextAware, In
         return true;
     }
 
-    // Pause
+    /**
+     * pause
+     *
+     * @param jobName
+     * @param jobGroup
+     * @return
+     * @throws SchedulerException
+     */
     public static boolean pauseJob(String jobName, String jobGroup) throws SchedulerException {
     	// TriggerKey : name + group
     	TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);
@@ -262,7 +300,14 @@ public final class XxlJobDynamicScheduler implements ApplicationContextAware, In
         return result;
     }
     
-    // resume
+    /**
+     * resume
+     *
+     * @param jobName
+     * @param jobGroup
+     * @return
+     * @throws SchedulerException
+     */
     public static boolean resumeJob(String jobName, String jobGroup) throws SchedulerException {
     	// TriggerKey : name + group
     	TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);
@@ -278,7 +323,14 @@ public final class XxlJobDynamicScheduler implements ApplicationContextAware, In
         return result;
     }
     
-    // run
+    /**
+     * run
+     *
+     * @param jobName
+     * @param jobGroup
+     * @return
+     * @throws SchedulerException
+     */
     public static boolean triggerJob(String jobName, String jobGroup) throws SchedulerException {
     	// TriggerKey : name + group
     	JobKey jobKey = new JobKey(jobName, jobGroup);
@@ -294,5 +346,41 @@ public final class XxlJobDynamicScheduler implements ApplicationContextAware, In
         return result;
     }
 
+    /**
+     * finaAllJobList
+     *
+     * @return
+     *//*
+    @Deprecated
+    public static List<Map<String, Object>> finaAllJobList(){
+        List<Map<String, Object>> jobList = new ArrayList<Map<String,Object>>();
+
+        try {
+            if (scheduler.getJobGroupNames()==null || scheduler.getJobGroupNames().size()==0) {
+                return null;
+            }
+            String groupName = scheduler.getJobGroupNames().get(0);
+            Set<JobKey> jobKeys = scheduler.getJobKeys(GroupMatcher.jobGroupEquals(groupName));
+            if (jobKeys!=null && jobKeys.size()>0) {
+                for (JobKey jobKey : jobKeys) {
+                    TriggerKey triggerKey = TriggerKey.triggerKey(jobKey.getName(), Scheduler.DEFAULT_GROUP);
+                    Trigger trigger = scheduler.getTrigger(triggerKey);
+                    JobDetail jobDetail = scheduler.getJobDetail(jobKey);
+                    TriggerState triggerState = scheduler.getTriggerState(triggerKey);
+                    Map<String, Object> jobMap = new HashMap<String, Object>();
+                    jobMap.put("TriggerKey", triggerKey);
+                    jobMap.put("Trigger", trigger);
+                    jobMap.put("JobDetail", jobDetail);
+                    jobMap.put("TriggerState", triggerState);
+                    jobList.add(jobMap);
+                }
+            }
+
+        } catch (SchedulerException e) {
+            e.printStackTrace();
+            return null;
+        }
+        return jobList;
+    }*/
 
 }

+ 1 - 1
xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobFailMonitorHelper.java

@@ -30,7 +30,7 @@ public class JobFailMonitorHelper {
 	private LinkedBlockingQueue<Integer> queue = new LinkedBlockingQueue<Integer>(0xfff8);
 
 	private Thread monitorThread;
-	private boolean toStop = false;
+	private volatile boolean toStop = false;
 	public void start(){
 		monitorThread = new Thread(new Runnable() {
 

+ 1 - 1
xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobRegistryMonitorHelper.java

@@ -28,7 +28,7 @@ public class JobRegistryMonitorHelper {
 	}
 
 	private Thread registryThread;
-	private boolean toStop = false;
+	private volatile boolean toStop = false;
 	public void start(){
 		registryThread = new Thread(new Runnable() {
 			@Override

+ 29 - 3
xxl-job-admin/src/main/java/com/xxl/job/admin/core/trigger/XxlJobTrigger.java

@@ -5,9 +5,9 @@ import com.xxl.job.admin.core.model.XxlJobGroup;
 import com.xxl.job.admin.core.model.XxlJobInfo;
 import com.xxl.job.admin.core.model.XxlJobLog;
 import com.xxl.job.admin.core.route.ExecutorRouteStrategyEnum;
-import com.xxl.job.admin.core.route.ExecutorRouter;
 import com.xxl.job.admin.core.schedule.XxlJobDynamicScheduler;
 import com.xxl.job.admin.core.thread.JobFailMonitorHelper;
+import com.xxl.job.core.biz.ExecutorBiz;
 import com.xxl.job.core.biz.model.ReturnT;
 import com.xxl.job.core.biz.model.TriggerParam;
 import com.xxl.job.core.enums.ExecutorBlockStrategyEnum;
@@ -90,12 +90,12 @@ public class XxlJobTrigger {
                     triggerParam.setBroadcastTotal(addressList.size()); // update02
 
                     // 4.2、trigger-run (route run / trigger remote executor)
-                    triggerResult = ExecutorRouter.runExecutor(triggerParam, address);     // update03
+                    triggerResult = runExecutor(triggerParam, address);     // update03
                     triggerMsgSb.append("<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>").append(triggerResult.getMsg());
 
                     // 4.3、trigger (fail retry)
                     if (triggerResult.getCode()!=ReturnT.SUCCESS_CODE && failStrategy == ExecutorFailStrategyEnum.FAIL_RETRY) {
-                        triggerResult = ExecutorRouter.runExecutor(triggerParam, address);  // update04
+                        triggerResult = runExecutor(triggerParam, address);  // update04
                         triggerMsgSb.append("<br><br><span style=\"color:#F39C12;\" > >>>>>>>>>>>失败重试<<<<<<<<<<< </span><br>").append(triggerResult.getMsg());
                     }
                 }
@@ -179,4 +179,30 @@ public class XxlJobTrigger {
         logger.debug(">>>>>>>>>>> xxl-job trigger end, jobId:{}", jobLog.getId());
     }
 
+    /**
+     * run executor
+     * @param triggerParam
+     * @param address
+     * @return  ReturnT.content: final address
+     */
+    public static ReturnT<String> runExecutor(TriggerParam triggerParam, String address){
+        ReturnT<String> runResult = null;
+        try {
+            ExecutorBiz executorBiz = XxlJobDynamicScheduler.getExecutorBiz(address);
+            runResult = executorBiz.run(triggerParam);
+        } catch (Exception e) {
+            logger.error(e.getMessage(), e);
+            runResult = new ReturnT<String>(ReturnT.FAIL_CODE, ""+e );
+        }
+
+        StringBuffer runResultSB = new StringBuffer("触发调度:");
+        runResultSB.append("<br>address:").append(address);
+        runResultSB.append("<br>code:").append(runResult.getCode());
+        runResultSB.append("<br>msg:").append(runResult.getMsg());
+
+        runResult.setMsg(runResultSB.toString());
+        runResult.setContent(address);
+        return runResult;
+    }
+
 }

+ 1 - 0
xxl-job-admin/src/main/resources/spring/applicationcontext-xxl-job-admin.xml

@@ -65,6 +65,7 @@
 	<bean id="xxlJobDynamicScheduler" class="com.xxl.job.admin.core.schedule.XxlJobDynamicScheduler" init-method="init" destroy-method="destroy" >
 		<!-- (轻易不要变更“调度器名称”, 任务创建时会绑定该“调度器名称”) -->
 		<property name="scheduler" ref="quartzScheduler"/>
+		<property name="accessToken" value="${xxl.job.accessToken}" />
 	</bean>
 	
 </beans>

+ 5 - 2
xxl-job-admin/src/main/resources/xxl-job-admin.properties

@@ -12,6 +12,9 @@ xxl.job.mail.password=asdfzxcv
 xxl.job.mail.sendFrom=ovono802302@163.com
 xxl.job.mail.sendNick=《任务调度平台XXL-JOB》
 
-# xxl-job login
+### xxl-job login
 xxl.job.login.username=admin
-xxl.job.login.password=123456
+xxl.job.login.password=123456
+
+### xxl-job, access token
+xxl.job.accessToken=

+ 4 - 3
xxl-job-admin/src/main/webapp/WEB-INF/template/common/common.macro.ftl

@@ -175,11 +175,12 @@
 
 <#macro commonFooter >
 	<footer class="main-footer">
-        Powered by <b>XXL-JOB</b> 1.8.1(快照版)
+        Powered by <b>XXL-JOB</b> 1.8.2(快照版本)
 		<div class="pull-right hidden-xs">
             <strong>Copyright &copy; 2015-${.now?string('yyyy')} &nbsp;
-                <a href="https://github.com/xuxueli/xxl-job" target="_blank" >github</a>&nbsp;
-                <a href="http://my.oschina.net/xuxueli/blog/690978" target="_blank" >oschina</a>
+                <a href="http://www.xuxueli.com/" target="_blank" >xuxueli</a>
+				&nbsp;
+                <a href="https://github.com/xuxueli/xxl-job" target="_blank" >github</a>
             </strong><!-- All rights reserved. -->
 		</div>
 	</footer>

+ 4 - 23
xxl-job-admin/src/main/webapp/WEB-INF/template/help.ftl

@@ -31,33 +31,14 @@
 				<h4>简介:XXL-JOB</h4>
 				<br>
 				<p>
-					<a target="_blank" href="https://github.com/xuxueli/xxl-job">github地址</a>&nbsp;&nbsp;&nbsp;&nbsp;
+                    <a target="_blank" href="http://www.xuxueli.com/">xuxueli</a>
+                    <br><br>
+					<a target="_blank" href="https://github.com/xuxueli/xxl-job">github</a>&nbsp;&nbsp;&nbsp;&nbsp;
 					<iframe src="https://ghbtns.com/github-btn.html?user=xuxueli&repo=xxl-job&type=star&count=true" frameborder="0" scrolling="0" width="170px" height="20px" style="margin-bottom:-5px;"></iframe> 
 					<br><br>
-					<a target="_blank" href="http://my.oschina.net/xuxueli/blog/690978">oschina地址</a>
-                    <br><br>
-
-                    <a >技术交流群5:138274130</a>&nbsp;&nbsp;&nbsp;&nbsp;
-                    <a target="_blank" href="//shang.qq.com/wpa/qunwpa?idkey=a3f3aea7e5943e7a24e9726495747ddc19bccd3592d7a70ecb5a97b616062241">
-						<img border="0" src="//pub.idqqimg.com/wpa/images/group.png" alt="《xxl-javaer》(五群)" title="《xxl-javaer》(五群)">
-					</a>
-                    <br><br>
-
-                    <a >技术交流群4:464762661</a>&nbsp;&nbsp;&nbsp;&nbsp;
-                    (群即将满,请加群5)
+                    <a target="_blank" href="http://my.oschina.net/xuxueli/blog/690978">oschina(文档中有交流群)</a>
                     <br><br>
 
-                    <a >技术交流群3:242151780</a>&nbsp;&nbsp;&nbsp;&nbsp;
-                    (群即将满,请加群5)
-                    <br><br>
-
-                    <a >技术交流群2:438249535</a>&nbsp;&nbsp;&nbsp;&nbsp;
-                    (群即将满,请加群5)
-                    <br><br>
-
-                    <a >技术交流群1:367260654</a>&nbsp;&nbsp;&nbsp;&nbsp;
-                    (群即将满,请加群5)
-
 				</p>
 				<p></p>
             </div>

+ 2 - 2
xxl-job-admin/src/main/webapp/WEB-INF/template/jobinfo/jobinfo.index.ftl

@@ -37,7 +37,7 @@
 	                	<span class="input-group-addon">执行器</span>
                 		<select class="form-control" id="jobGroup" >
                 			<#list JobGroupList as group>
-                				<option value="${group.id}" >${group.title}</option>
+                				<option value="${group.id}" <#if jobGroup==group.id>selected</#if> >${group.title}</option>
                 			</#list>
 	                  	</select>
 	              	</div>
@@ -110,7 +110,7 @@
 						<div class="col-sm-4">
 							<select class="form-control" name="jobGroup" >
 		            			<#list JobGroupList as group>
-		            				<option value="${group.id}" >${group.title}</option>
+		            				<option value="${group.id}" <#if jobGroup==group.id>selected</#if> >${group.title}</option>
 		            			</#list>
 		                  	</select>
 						</div>

+ 7 - 0
xxl-job-admin/src/main/webapp/static/js/jobinfo.index.1.js

@@ -167,6 +167,13 @@ $(function() {
 		jobTable.fnDraw();
 	});
 	
+	// jobGroup change
+	$('#jobGroup').on('change', function(){
+        //reload
+        var jobGroup = $('#jobGroup').val();
+        window.location.href = base_url + "/jobinfo?jobGroup=" + jobGroup;
+    });
+	
 	// job operate
 	$("#job_list").on('click', '.job_operate',function() {
 		var typeName;

+ 32 - 0
xxl-job-admin/src/test/java/com/xxl/job/dao/impl/AdminBizTest.java

@@ -0,0 +1,32 @@
+package com.xxl.job.dao.impl;
+
+import com.xxl.job.core.biz.AdminBiz;
+import com.xxl.job.core.biz.model.RegistryParam;
+import com.xxl.job.core.biz.model.ReturnT;
+import com.xxl.job.core.enums.RegistryConfig;
+import com.xxl.job.core.rpc.netcom.NetComClientProxy;
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * admin-api client, test
+ * @author xuxueli 2017-07-28 22:14:52
+ */
+public class AdminBizTest {
+
+    @Test
+    public void registryTest() throws Exception {
+
+        // admin-client
+        String addressUrl = "http://127.0.0.1:8080/xxl-job-admin".concat(AdminBiz.MAPPING);
+        String accessToken = null;
+        AdminBiz adminBiz = (AdminBiz) new NetComClientProxy(AdminBiz.class, addressUrl, accessToken).getObject();
+
+        // test executor registry
+        RegistryParam registryParam = new RegistryParam(RegistryConfig.RegistType.EXECUTOR.name(), "xxl-job-executor-example", "127.0.0.1:9999");
+        ReturnT<String> returnT = adminBiz.registry(registryParam);
+        Assert.assertTrue(returnT.getCode() == ReturnT.SUCCESS_CODE);
+
+    }
+
+}

+ 10 - 14
xxl-job-core/pom.xml

@@ -4,7 +4,7 @@
 	<parent>
 		<groupId>com.xuxueli</groupId>
 		<artifactId>xxl-job</artifactId>
-		<version>1.8.1-SNAPSHOT</version>
+		<version>1.8.2-SNAPSHOT</version>
 	</parent>
 	<artifactId>xxl-job-core</artifactId>
 	<packaging>jar</packaging>
@@ -13,56 +13,52 @@
 	<description>A lightweight distributed task scheduling framework.</description>
 	<url>http://www.xuxueli.com/</url>
 
-	<properties>
-		<spring.version>3.2.17.RELEASE</spring.version>
-	</properties>
-
 	<dependencies>
 		<!-- servlet -->
 		<dependency>
 			<groupId>javax.servlet</groupId>
 			<artifactId>javax.servlet-api</artifactId>
-			<version>3.0.1</version>
+			<version>${javax.servlet-api.version}</version>
 		</dependency>
 		<dependency>
 			<groupId>javax.servlet.jsp</groupId>
 			<artifactId>jsp-api</artifactId>
-			<version>2.2</version>
+			<version>${jsp-api.version}</version>
 		</dependency>
 
 		<!-- jetty -->
 		<dependency>
 			<groupId>org.eclipse.jetty</groupId>
 			<artifactId>jetty-server</artifactId>
-			<version>9.2.21.v20170120</version>
+			<version>${jetty-server.version}</version>
 		</dependency>
 
 		<!-- slf4j -->
 		<dependency>
 			<groupId>org.slf4j</groupId>
 			<artifactId>slf4j-api</artifactId>
-			<version>1.7.21</version>
+			<version>${slf4j-api.version}</version>
 		</dependency>
 
 		<!-- hessian -->
 		<dependency>
 			<groupId>com.caucho</groupId>
 			<artifactId>hessian</artifactId>
-			<version>4.0.38</version>
+			<version>${hessian.version}</version>
 		</dependency>
 
 		<!-- jackson -->
 		<dependency>
 			<groupId>org.codehaus.jackson</groupId>
 			<artifactId>jackson-mapper-asl</artifactId>
-			<version>1.9.13</version>
+			<version>${jackson-mapper-asl.version}</version>
 		</dependency>
 		
 		<!-- httpclient -->
 		<dependency>
 			<groupId>org.apache.httpcomponents</groupId>
 			<artifactId>httpclient</artifactId>
-			<version>4.3.6</version>
+			<version>${httpclient.version}</version>
 		</dependency>
 		
 		<!-- spring-context -->
@@ -76,14 +72,14 @@
 		<dependency>
 			<groupId>org.codehaus.groovy</groupId>
 			<artifactId>groovy-all</artifactId>
-			<version>2.4.5</version>
+			<version>${groovy-all.version}</version>
 		</dependency>
 
 		<!-- commons-exec -->
 		<dependency>
 			<groupId>org.apache.commons</groupId>
 			<artifactId>commons-exec</artifactId>
-			<version>1.3</version>
+			<version>${commons-exec.version}</version>
 		</dependency>
 
 	</dependencies>

+ 2 - 0
xxl-job-core/src/main/java/com/xxl/job/core/biz/AdminBiz.java

@@ -11,6 +11,8 @@ import java.util.List;
  */
 public interface AdminBiz {
 
+    public static final String MAPPING = "/api";
+
     /**
      * callback
      *

+ 86 - 51
xxl-job-core/src/main/java/com/xxl/job/core/executor/XxlJobExecutor.java

@@ -1,36 +1,38 @@
 package com.xxl.job.core.executor;
 
+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.JobHander;
+import com.xxl.job.core.log.XxlJobFileAppender;
+import com.xxl.job.core.rpc.netcom.NetComClientProxy;
 import com.xxl.job.core.rpc.netcom.NetComServerFactory;
-import com.xxl.job.core.thread.ExecutorRegistryThread;
 import com.xxl.job.core.thread.JobThread;
-import com.xxl.job.core.thread.TriggerCallbackThread;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.BeansException;
 import org.springframework.context.ApplicationContext;
 import org.springframework.context.ApplicationContextAware;
-import org.springframework.context.ApplicationEvent;
-import org.springframework.context.ApplicationListener;
-import org.springframework.context.event.ContextClosedEvent;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 
 /**
  * Created by xuxueli on 2016/3/2 21:14.
  */
-public class XxlJobExecutor implements ApplicationContextAware, ApplicationListener {
+public class XxlJobExecutor implements ApplicationContextAware {
     private static final Logger logger = LoggerFactory.getLogger(XxlJobExecutor.class);
 
+    // ---------------------- param ----------------------
     private String ip;
     private int port = 9999;
     private String appName;
-    public static String adminAddresses;
-    public static String logPath;
+    private String adminAddresses;
+    private String accessToken;
+    private String logPath;
 
     public void setIp(String ip) {
         this.ip = ip;
@@ -44,48 +46,98 @@ public class XxlJobExecutor implements ApplicationContextAware, ApplicationListe
     public void setAdminAddresses(String adminAddresses) {
         this.adminAddresses = adminAddresses;
     }
+    public void setAccessToken(String accessToken) {
+        this.accessToken = accessToken;
+    }
     public void setLogPath(String logPath) {
         this.logPath = logPath;
     }
 
-    // ---------------------------------- job server ------------------------------------
-    private NetComServerFactory serverFactory = new NetComServerFactory();
-    public void start() throws Exception {
-        // executor start
-        NetComServerFactory.putService(ExecutorBiz.class, new ExecutorBizImpl());   // rpc-service, base on jetty
-        serverFactory.start(port, ip, appName);
 
-        // trigger callback thread start
-        TriggerCallbackThread.getInstance().start();
+    // ---------------------- applicationContext ----------------------
+    private static ApplicationContext applicationContext;
+    @Override
+    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+        this.applicationContext = applicationContext;
     }
-    public void destroy(){
-        // 1、executor registry thread stop
-        ExecutorRegistryThread.getInstance().toStop();
+    public static ApplicationContext getApplicationContext() {
+        return applicationContext;
+    }
+
+
+    // ---------------------- start + stop ----------------------
+    public void start() throws Exception {
+        // init admin-client
+        initAdminBizList(adminAddresses, accessToken);
+
+        // init executor-jobHandlerRepository
+        initJobHandlerRepository(applicationContext);
 
-        // 2、executor stop
-        serverFactory.destroy();
+        // init logpath
+        if (logPath!=null && logPath.trim().length()>0) {
+            XxlJobFileAppender.logPath = logPath;
+        }
 
-        // 3、job thread repository destory
+        // init executor-server
+        initExecutorServer(port, ip, appName, accessToken);
+    }
+    public void destroy(){
+        // destory JobThreadRepository
         if (JobThreadRepository.size() > 0) {
             for (Map.Entry<Integer, JobThread> item: JobThreadRepository.entrySet()) {
-                JobThread jobThread = item.getValue();
-                jobThread.toStop("Web容器销毁终止");
-                jobThread.interrupt();
-
+                removeJobThread(item.getKey(), "Web容器销毁终止");
             }
             JobThreadRepository.clear();
         }
 
-        // 4、trigger callback thread stop
-        TriggerCallbackThread.getInstance().toStop();
+        // destory executor-server
+        stopExecutorServer();
+    }
+
+
+    // ---------------------- admin-client ----------------------
+    private static List<AdminBiz> adminBizList;
+    private static 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) {
+                    String addressUrl = address.concat(AdminBiz.MAPPING);
+                    AdminBiz adminBiz = (AdminBiz) new NetComClientProxy(AdminBiz.class, addressUrl, accessToken).getObject();
+                    if (adminBizList == null) {
+                        adminBizList = new ArrayList<AdminBiz>();
+                    }
+                    adminBizList.add(adminBiz);
+                }
+            }
+        }
+    }
+    public static List<AdminBiz> getAdminBizList(){
+        return adminBizList;
+    }
+
+
+    // ---------------------- executor-server(jetty) ----------------------
+    private NetComServerFactory serverFactory = new NetComServerFactory();
+    private void initExecutorServer(int port, String ip, String appName, String accessToken) throws Exception {
+        NetComServerFactory.putService(ExecutorBiz.class, new ExecutorBizImpl());   // rpc-service, base on jetty
+        NetComServerFactory.setAccessToken(accessToken);
+        serverFactory.start(port, ip, appName); // jetty + registry
+    }
+    private void stopExecutorServer() {
+        serverFactory.destroy();    // jetty + registry + callback
     }
 
-    // ---------------------------------- init job handler ------------------------------------
-    public static ApplicationContext applicationContext;
-	@Override
-	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
-        XxlJobExecutor.applicationContext = applicationContext;
 
+    // ---------------------- job handler repository ----------------------
+    private static ConcurrentHashMap<String, IJobHandler> jobHandlerRepository = new ConcurrentHashMap<String, IJobHandler>();
+    public static IJobHandler registJobHandler(String name, IJobHandler jobHandler){
+        logger.info("xxl-job register jobhandler success, name:{}, jobHandler:{}", name, jobHandler);
+        return jobHandlerRepository.put(name, jobHandler);
+    }
+    public static IJobHandler loadJobHandler(String name){
+        return jobHandlerRepository.get(name);
+    }
+    private static void initJobHandlerRepository(ApplicationContext applicationContext){
         // init job handler action
         Map<String, Object> serviceBeanMap = applicationContext.getBeansWithAnnotation(JobHander.class);
 
@@ -101,27 +153,10 @@ public class XxlJobExecutor implements ApplicationContextAware, ApplicationListe
                 }
             }
         }
-	}
-
-    // ---------------------------------- destory job executor ------------------------------------
-    @Override
-    public void onApplicationEvent(ApplicationEvent applicationEvent) {
-        if(applicationEvent instanceof ContextClosedEvent){
-            // TODO
-        }
     }
 
-    // ---------------------------------- job handler repository
-    private static ConcurrentHashMap<String, IJobHandler> jobHandlerRepository = new ConcurrentHashMap<String, IJobHandler>();
-    public static IJobHandler registJobHandler(String name, IJobHandler jobHandler){
-        logger.info("xxl-job register jobhandler success, name:{}, jobHandler:{}", name, jobHandler);
-        return jobHandlerRepository.put(name, jobHandler);
-    }
-    public static IJobHandler loadJobHandler(String name){
-        return jobHandlerRepository.get(name);
-    }
 
-    // ---------------------------------- job thread repository
+    // ---------------------- job thread repository ----------------------
     private static ConcurrentHashMap<Integer, JobThread> JobThreadRepository = new ConcurrentHashMap<Integer, JobThread>();
     public static JobThread registJobThread(int jobId, IJobHandler handler, String removeOldReason){
         JobThread newJobThread = new JobThread(jobId, handler);

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

@@ -52,21 +52,21 @@ public class GlueFactory {
 				try {
 					Resource resource = AnnotationUtils.getAnnotation(field, Resource.class);
 					if (resource.name()!=null && resource.name().length()>0){
-						fieldBean = XxlJobExecutor.applicationContext.getBean(resource.name());
+						fieldBean = XxlJobExecutor.getApplicationContext().getBean(resource.name());
 					} else {
-						fieldBean = XxlJobExecutor.applicationContext.getBean(field.getName());
+						fieldBean = XxlJobExecutor.getApplicationContext().getBean(field.getName());
 					}
 				} catch (Exception e) {
 				}
 				if (fieldBean==null ) {
-					fieldBean = XxlJobExecutor.applicationContext.getBean(field.getType());
+					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.applicationContext.getBean(qualifier.value());
+					fieldBean = XxlJobExecutor.getApplicationContext().getBean(qualifier.value());
 				} else {
-					fieldBean = XxlJobExecutor.applicationContext.getBean(field.getType());
+					fieldBean = XxlJobExecutor.getApplicationContext().getBean(field.getType());
 				}
 			}
 			

+ 3 - 4
xxl-job-core/src/main/java/com/xxl/job/core/handler/impl/ScriptJobHandler.java

@@ -1,7 +1,6 @@
 package com.xxl.job.core.handler.impl;
 
 import com.xxl.job.core.biz.model.ReturnT;
-import com.xxl.job.core.executor.XxlJobExecutor;
 import com.xxl.job.core.glue.GlueTypeEnum;
 import com.xxl.job.core.handler.IJobHandler;
 import com.xxl.job.core.log.XxlJobFileAppender;
@@ -37,17 +36,17 @@ public class ScriptJobHandler extends IJobHandler {
         String scriptFileName = null;
         if (GlueTypeEnum.GLUE_SHELL == glueType) {
             cmd = "bash";
-            scriptFileName = XxlJobExecutor.logPath.concat("gluesource/").concat(String.valueOf(jobId)).concat("_").concat(String.valueOf(glueUpdatetime)).concat(".sh");
+            scriptFileName = XxlJobFileAppender.logPath.concat("gluesource/").concat(String.valueOf(jobId)).concat("_").concat(String.valueOf(glueUpdatetime)).concat(".sh");
         } else if (GlueTypeEnum.GLUE_PYTHON == glueType) {
             cmd = "python";
-            scriptFileName = XxlJobExecutor.logPath.concat("gluesource/").concat(String.valueOf(jobId)).concat("_").concat(String.valueOf(glueUpdatetime)).concat(".py");
+            scriptFileName = XxlJobFileAppender.logPath.concat("gluesource/").concat(String.valueOf(jobId)).concat("_").concat(String.valueOf(glueUpdatetime)).concat(".py");
         }
 
         // make script file
         ScriptUtil.markScriptFile(scriptFileName, gluesource);
 
         // log file
-        String logFileName = XxlJobExecutor.logPath.concat(XxlJobFileAppender.contextHolder.get());
+        String logFileName = XxlJobFileAppender.logPath.concat(XxlJobFileAppender.contextHolder.get());
 
         // invoke
         XxlJobLogger.log("----------- script file:"+ scriptFileName +" -----------");

+ 5 - 5
xxl-job-core/src/main/java/com/xxl/job/core/log/XxlJobFileAppender.java

@@ -1,7 +1,6 @@
 package com.xxl.job.core.log;
 
 import com.xxl.job.core.biz.model.LogResult;
-import com.xxl.job.core.executor.XxlJobExecutor;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -20,7 +19,8 @@ public class XxlJobFileAppender {
 	//public static ThreadLocal<String> contextHolder = new ThreadLocal<String>();
 	public static final InheritableThreadLocal<String> contextHolder = new InheritableThreadLocal<String>();
 	public static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
-	
+	public static String logPath = "/data/applogs/xxl-job/jobhandler/";
+
 	/**
 	 * log filename: yyyy-MM-dd/9999.log
 	 *
@@ -31,7 +31,7 @@ public class XxlJobFileAppender {
 	public static String makeLogFileName(Date triggerDate, int logId) {
 
         // filePath/
-        File filePathDir = new File(XxlJobExecutor.logPath);
+        File filePathDir = new File(logPath);
         if (!filePathDir.exists()) {
             filePathDir.mkdirs();
         }
@@ -66,7 +66,7 @@ public class XxlJobFileAppender {
 		if (logFileName==null || logFileName.trim().length()==0) {
 			return;
 		}
-		File logFile = new File(XxlJobExecutor.logPath, logFileName);
+		File logFile = new File(logPath, logFileName);
 
 		if (!logFile.exists()) {
 			try {
@@ -111,7 +111,7 @@ public class XxlJobFileAppender {
 		if (logFileName==null || logFileName.trim().length()==0) {
             return new LogResult(fromLineNum, 0, "readLog fail, logFile not found", true);
 		}
-		File logFile = new File(XxlJobExecutor.logPath, logFileName);
+		File logFile = new File(logPath, logFileName);
 
 		if (!logFile.exists()) {
             return new LogResult(fromLineNum, 0, "readLog fail, logFile not exists", true);

+ 30 - 7
xxl-job-core/src/main/java/com/xxl/job/core/rpc/codec/RpcRequest.java

@@ -12,12 +12,14 @@ public class RpcRequest implements Serializable{
 	
 	private String serverAddress;
 	private long createMillisTime;
+	private String accessToken;
 
     private String className;
     private String methodName;
     private Class<?>[] parameterTypes;
     private Object[] parameters;
 
+
 	public String getServerAddress() {
 		return serverAddress;
 	}
@@ -29,41 +31,62 @@ public class RpcRequest implements Serializable{
 	public long getCreateMillisTime() {
 		return createMillisTime;
 	}
+
 	public void setCreateMillisTime(long createMillisTime) {
 		this.createMillisTime = createMillisTime;
 	}
+
+	public String getAccessToken() {
+		return accessToken;
+	}
+
+	public void setAccessToken(String accessToken) {
+		this.accessToken = accessToken;
+	}
+
 	public String getClassName() {
 		return className;
 	}
+
 	public void setClassName(String className) {
 		this.className = className;
 	}
+
 	public String getMethodName() {
 		return methodName;
 	}
+
 	public void setMethodName(String methodName) {
 		this.methodName = methodName;
 	}
+
 	public Class<?>[] getParameterTypes() {
 		return parameterTypes;
 	}
+
 	public void setParameterTypes(Class<?>[] parameterTypes) {
 		this.parameterTypes = parameterTypes;
 	}
+
 	public Object[] getParameters() {
 		return parameters;
 	}
+
 	public void setParameters(Object[] parameters) {
 		this.parameters = parameters;
 	}
-	
+
 	@Override
 	public String toString() {
-		return "NettyRequest [serverAddress=" + serverAddress + ", createMillisTime="
-				+ createMillisTime + ", className=" + className
-				+ ", methodName=" + methodName + ", parameterTypes="
-				+ Arrays.toString(parameterTypes) + ", parameters="
-				+ Arrays.toString(parameters) + "]";
+		return "RpcRequest{" +
+				"serverAddress='" + serverAddress + '\'' +
+				", createMillisTime=" + createMillisTime +
+				", accessToken='" + accessToken + '\'' +
+				", className='" + className + '\'' +
+				", methodName='" + methodName + '\'' +
+				", parameterTypes=" + Arrays.toString(parameterTypes) +
+				", parameters=" + Arrays.toString(parameters) +
+				'}';
 	}
-	
+
 }

+ 6 - 3
xxl-job-core/src/main/java/com/xxl/job/core/rpc/netcom/NetComClientProxy.java

@@ -20,11 +20,13 @@ public class NetComClientProxy implements FactoryBean<Object> {
 
 	// ---------------------- config ----------------------
 	private Class<?> iface;
-	String serverAddress;
-	JettyClient client = new JettyClient();
-	public NetComClientProxy(Class<?> iface, String serverAddress) {
+	private String serverAddress;
+	private String accessToken;
+	private JettyClient client = new JettyClient();
+	public NetComClientProxy(Class<?> iface, String serverAddress, String accessToken) {
 		this.iface = iface;
 		this.serverAddress = serverAddress;
+		this.accessToken = accessToken;
 	}
 
 	@Override
@@ -39,6 +41,7 @@ public class NetComClientProxy implements FactoryBean<Object> {
 						RpcRequest request = new RpcRequest();
 	                    request.setServerAddress(serverAddress);
 	                    request.setCreateMillisTime(System.currentTimeMillis());
+	                    request.setAccessToken(accessToken);
 	                    request.setClassName(method.getDeclaringClass().getName());
 	                    request.setMethodName(method.getName());
 	                    request.setParameterTypes(method.getParameterTypes());

+ 10 - 2
xxl-job-core/src/main/java/com/xxl/job/core/rpc/netcom/NetComServerFactory.java

@@ -30,14 +30,18 @@ public class NetComServerFactory  {
 		server.destroy();
 	}
 
-	// ---------------------- server init ----------------------
+	// ---------------------- server instance ----------------------
 	/**
 	 * init local rpc service map
 	 */
 	private static Map<String, Object> serviceMap = new HashMap<String, Object>();
+	private static String accessToken;
 	public static void putService(Class<?> iface, Object serviceBean){
 		serviceMap.put(iface.getName(), serviceBean);
 	}
+	public static void setAccessToken(String accessToken) {
+		NetComServerFactory.accessToken = accessToken;
+	}
 	public static RpcResponse invokeService(RpcRequest request, Object serviceBean) {
 		if (serviceBean==null) {
 			serviceBean = serviceMap.get(request.getClassName());
@@ -49,7 +53,11 @@ public class NetComServerFactory  {
 		RpcResponse response = new RpcResponse();
 
 		if (System.currentTimeMillis() - request.getCreateMillisTime() > 180000) {
-			response.setResult(new ReturnT<String>(ReturnT.FAIL_CODE, "the timestamp difference between admin and executor exceeds the limit."));
+			response.setResult(new ReturnT<String>(ReturnT.FAIL_CODE, "The timestamp difference between admin and executor exceeds the limit."));
+			return response;
+		}
+		if (accessToken!=null && accessToken.trim().length()>0 && !accessToken.trim().equals(request.getAccessToken())) {
+			response.setResult(new ReturnT<String>(ReturnT.FAIL_CODE, "The access token[" + request.getAccessToken() + "] is wrong."));
 			return response;
 		}
 

+ 2 - 2
xxl-job-core/src/main/java/com/xxl/job/core/rpc/netcom/jetty/client/JettyClient.java

@@ -21,8 +21,8 @@ public class JettyClient {
 
 			// reqURL
 			String reqURL = request.getServerAddress();
-			if (reqURL!=null && reqURL.toLowerCase().indexOf("http://")==-1) {
-				reqURL = "http://" + request.getServerAddress() + "/";
+			if (reqURL!=null && reqURL.toLowerCase().indexOf("http")==-1) {
+				reqURL = "http://" + request.getServerAddress() + "/";	// IP:PORT, need parse to url
 			}
 
 			// remote invoke

+ 17 - 1
xxl-job-core/src/main/java/com/xxl/job/core/rpc/netcom/jetty/server/JettyServer.java

@@ -1,6 +1,7 @@
 package com.xxl.job.core.rpc.netcom.jetty.server;
 
 import com.xxl.job.core.thread.ExecutorRegistryThread;
+import com.xxl.job.core.thread.TriggerCallbackThread;
 import org.eclipse.jetty.server.Connector;
 import org.eclipse.jetty.server.Handler;
 import org.eclipse.jetty.server.Server;
@@ -38,10 +39,16 @@ public class JettyServer {
 				server.setHandler(handlerc);
 
 				try {
-					// Start the server
+					// Start server
 					server.start();
 					logger.info(">>>>>>>>>>>> xxl-job jetty server start success at port:{}.", port);
+
+					// Start Registry-Server
 					ExecutorRegistryThread.getInstance().start(port, ip, appName);
+
+					// Start Callback-Server
+					TriggerCallbackThread.getInstance().start();
+
 					server.join();	// block until thread stopped
 					logger.info(">>>>>>>>>>> xxl-rpc server join success, netcon={}, port={}", JettyServer.class.getName(), port);
 				} catch (Exception e) {
@@ -56,6 +63,8 @@ public class JettyServer {
 	}
 
 	public void destroy() {
+
+		// destroy server
 		if (server != null) {
 			try {
 				server.stop();
@@ -67,6 +76,13 @@ public class JettyServer {
 		if (thread.isAlive()) {
 			thread.interrupt();
 		}
+
+		// destroy Registry-Server
+		ExecutorRegistryThread.getInstance().toStop();
+
+		// destroy Callback-Server
+		TriggerCallbackThread.getInstance().toStop();
+
 		logger.info(">>>>>>>>>>> xxl-rpc server destroy success, netcon={}", JettyServer.class.getName());
 	}
 

+ 2 - 9
xxl-job-core/src/main/java/com/xxl/job/core/thread/ExecutorRegistryThread.java

@@ -5,7 +5,6 @@ import com.xxl.job.core.biz.model.RegistryParam;
 import com.xxl.job.core.biz.model.ReturnT;
 import com.xxl.job.core.enums.RegistryConfig;
 import com.xxl.job.core.executor.XxlJobExecutor;
-import com.xxl.job.core.rpc.netcom.NetComClientProxy;
 import com.xxl.job.core.util.IpUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -32,7 +31,7 @@ public class ExecutorRegistryThread extends Thread {
             logger.warn(">>>>>>>>>>>> xxl-job, executor registry config fail, appName is null.");
             return;
         }
-        if (XxlJobExecutor.adminAddresses==null || XxlJobExecutor.adminAddresses.trim().length()==0) {
+        if (XxlJobExecutor.getAdminBizList() == null) {
             logger.warn(">>>>>>>>>>>> xxl-job, executor registry config fail, adminAddresses is null.");
             return;
         }
@@ -49,15 +48,10 @@ public class ExecutorRegistryThread extends Thread {
             @Override
             public void run() {
                 while (!toStop) {
-
                     try {
                         RegistryParam registryParam = new RegistryParam(RegistryConfig.RegistType.EXECUTOR.name(), appName, executorAddress);
-
-                        for (String addressUrl: XxlJobExecutor.adminAddresses.split(",")) {
-                            String apiUrl = addressUrl.concat("/api");
-
+                        for (AdminBiz adminBiz: XxlJobExecutor.getAdminBizList()) {
                             try {
-                                AdminBiz adminBiz = (AdminBiz) new NetComClientProxy(AdminBiz.class, apiUrl).getObject();
                                 ReturnT<String> registryResult = adminBiz.registry(registryParam);
                                 if (registryResult!=null && ReturnT.SUCCESS_CODE == registryResult.getCode()) {
                                     registryResult = ReturnT.SUCCESS;
@@ -71,7 +65,6 @@ public class ExecutorRegistryThread extends Thread {
                             }
 
                         }
-
                     } catch (Exception e) {
                         logger.error(e.getMessage(), e);
                     }

+ 2 - 6
xxl-job-core/src/main/java/com/xxl/job/core/thread/TriggerCallbackThread.java

@@ -4,7 +4,6 @@ import com.xxl.job.core.biz.AdminBiz;
 import com.xxl.job.core.biz.model.HandleCallbackParam;
 import com.xxl.job.core.biz.model.ReturnT;
 import com.xxl.job.core.executor.XxlJobExecutor;
-import com.xxl.job.core.rpc.netcom.NetComClientProxy;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -43,17 +42,14 @@ public class TriggerCallbackThread {
                             callbackParamList.add(callback);
 
                             // valid
-                            if (XxlJobExecutor.adminAddresses==null || XxlJobExecutor.adminAddresses.trim().length()==0) {
+                            if (XxlJobExecutor.getAdminBizList()==null) {
                                 logger.warn(">>>>>>>>>>>> xxl-job callback fail, adminAddresses is null, callbackParamList:{}", callbackParamList);
                                 continue;
                             }
 
                             // callback, will retry if error
-                            for (String addressUrl: XxlJobExecutor.adminAddresses.split(",")) {
-                                String apiUrl = addressUrl.concat("/api");
-
+                            for (AdminBiz adminBiz: XxlJobExecutor.getAdminBizList()) {
                                 try {
-                                    AdminBiz adminBiz = (AdminBiz) new NetComClientProxy(AdminBiz.class, apiUrl).getObject();
                                     ReturnT<String> callbackResult = adminBiz.callback(callbackParamList);
                                     if (callbackResult!=null && ReturnT.SUCCESS_CODE == callbackResult.getCode()) {
                                         callbackResult = ReturnT.SUCCESS;

+ 2 - 2
xxl-job-core/src/main/java/com/xxl/job/core/util/ScriptUtil.java

@@ -1,6 +1,6 @@
 package com.xxl.job.core.util;
 
-import com.xxl.job.core.executor.XxlJobExecutor;
+import com.xxl.job.core.log.XxlJobFileAppender;
 import org.apache.commons.exec.CommandLine;
 import org.apache.commons.exec.DefaultExecutor;
 import org.apache.commons.exec.PumpStreamHandler;
@@ -28,7 +28,7 @@ public class ScriptUtil {
      */
     public static void markScriptFile(String scriptFileName, String content) throws IOException {
         // filePath/
-        File filePathDir = new File(XxlJobExecutor.logPath);
+        File filePathDir = new File(XxlJobFileAppender.logPath);
         if (!filePathDir.exists()) {
             filePathDir.mkdirs();
         }

+ 3 - 21
xxl-job-executor-example/pom.xml

@@ -4,7 +4,7 @@
 	<parent>
 		<groupId>com.xuxueli</groupId>
 		<artifactId>xxl-job</artifactId>
-		<version>1.8.1-SNAPSHOT</version>
+		<version>1.8.2-SNAPSHOT</version>
 	</parent>
 	<artifactId>xxl-job-executor-example</artifactId>
 	<packaging>war</packaging>
@@ -13,12 +13,8 @@
 	<description>Executor project for spring boot.</description>
 	<url>http://www.xuxueli.com/</url>
 
-	<properties>
-		<spring.version>3.2.17.RELEASE</spring.version>
-	</properties>
-
 	<dependencies>
-		<!-- springframe start -->
+		<!-- spring-webmvc -->
 		<dependency>
 			<groupId>org.springframework</groupId>
 			<artifactId>spring-webmvc</artifactId>
@@ -29,20 +25,7 @@
 		<dependency>
 			<groupId>org.slf4j</groupId>
 			<artifactId>slf4j-log4j12</artifactId>
-			<version>1.7.21</version>
-		</dependency>
-		
-		<!-- c3p0 -->
-		<dependency>
-			<groupId>com.mchange</groupId>
-			<artifactId>c3p0</artifactId>
-			<version>0.9.5.2</version>
-		</dependency>
-		<!-- mysql-connector -->
-		<dependency>
-			<groupId>mysql</groupId>
-			<artifactId>mysql-connector-java</artifactId>
-			<version>5.1.29</version>
+			<version>${slf4j-api.version}</version>
 		</dependency>
 		
 		<!-- xxl-job-core -->
@@ -51,7 +34,6 @@
 			<artifactId>xxl-job-core</artifactId>
 			<version>${project.parent.version}</version>
 		</dependency>
-		
 	</dependencies>
 
 </project>

+ 2 - 0
xxl-job-executor-example/src/main/resources/applicationcontext-xxl-job.xml

@@ -33,6 +33,8 @@
 		<property name="adminAddresses" value="${xxl.job.admin.addresses}" />
 		<!-- 执行器日志路径[必填] -->
 		<property name="logPath" value="${xxl.job.executor.logpath}" />
+		<!-- 访问令牌,非空则进行匹配校验[选填] -->
+		<property name="accessToken" value="${xxl.job.accessToken}" />
 	</bean>
 
 

+ 4 - 1
xxl-job-executor-example/src/main/resources/xxl-job-executor.properties

@@ -7,4 +7,7 @@ xxl.job.executor.ip=
 xxl.job.executor.port=9999
 
 ### xxl-job log path
-xxl.job.executor.logpath=/data/applogs/xxl-job/jobhandler/
+xxl.job.executor.logpath=/data/applogs/xxl-job/jobhandler/
+
+### xxl-job, access token
+xxl.job.accessToken=

+ 4 - 1
xxl-job-executor-example/src/test/java/com/xxl/executor/test/DemoJobHandlerTest.java

@@ -8,6 +8,8 @@ import com.xxl.job.core.glue.GlueTypeEnum;
 import com.xxl.job.core.rpc.netcom.NetComClientProxy;
 
 /**
+ * executor-api client, test
+ *
  * Created by xuxueli on 17/5/12.
  */
 public class DemoJobHandlerTest {
@@ -31,7 +33,8 @@ public class DemoJobHandlerTest {
         triggerParam.setLogDateTim(System.currentTimeMillis());
 
         // do remote trigger
-        ExecutorBiz executorBiz = (ExecutorBiz) new NetComClientProxy(ExecutorBiz.class, "127.0.0.1:9999").getObject();
+        String accessToken = null;
+        ExecutorBiz executorBiz = (ExecutorBiz) new NetComClientProxy(ExecutorBiz.class, "127.0.0.1:9999", null).getObject();
         ReturnT<String> runResult = executorBiz.run(triggerParam);
     }
 

+ 25 - 24
xxl-job-executor-springboot-example/pom.xml

@@ -6,7 +6,7 @@
     <parent>
         <groupId>com.xuxueli</groupId>
         <artifactId>xxl-job</artifactId>
-        <version>1.8.1-SNAPSHOT</version>
+        <version>1.8.2-SNAPSHOT</version>
     </parent>
     <artifactId>xxl-job-executor-springboot-example</artifactId>
     <packaging>jar</packaging>
@@ -16,8 +16,6 @@
     <url>http://www.xuxueli.com/</url>
 
     <properties>
-        <spring-boot.version>1.3.8.RELEASE</spring-boot.version>
-
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
         <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
         <java.version>1.7</java.version>
@@ -33,41 +31,44 @@
                 <type>pom</type>
                 <scope>import</scope>
             </dependency>
+
+            <!-- jetty -->
+            <dependency>
+                <groupId>org.eclipse.jetty</groupId>
+                <artifactId>jetty-server</artifactId>
+                <version>${jetty-server.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.eclipse.jetty</groupId>
+                <artifactId>jetty-util</artifactId>
+                <version>${jetty-server.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.eclipse.jetty</groupId>
+                <artifactId>jetty-http</artifactId>
+                <version>${jetty-server.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.eclipse.jetty</groupId>
+                <artifactId>jetty-io</artifactId>
+                <version>${jetty-server.version}</version>
+            </dependency>
+
         </dependencies>
     </dependencyManagement>
 
     <dependencies>
-
-        <dependency>
-            <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-starter</artifactId>
-        </dependency>
-
-        <!-- spring-boot-starter-web (提供了对web的支持,包含了spring webmvc和tomcat等web开发的特性) -->
+        <!-- spring-boot-starter-web (spring-webmvc + tomcat) -->
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-web</artifactId>
         </dependency>
-
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-test</artifactId>
             <scope>test</scope>
         </dependency>
 
-        <!-- c3p0 -->
-        <dependency>
-            <groupId>com.mchange</groupId>
-            <artifactId>c3p0</artifactId>
-            <version>0.9.5.2</version>
-        </dependency>
-        <!-- mysql-connector -->
-        <dependency>
-            <groupId>mysql</groupId>
-            <artifactId>mysql-connector-java</artifactId>
-            <version>5.1.29</version>
-        </dependency>
-
         <!-- xxl-job-core -->
         <dependency>
             <groupId>com.xuxueli</groupId>

+ 3 - 0
xxl-job-executor-springboot-example/src/main/java/com/xxl/job/executor/core/config/XxlJobConfig.java

@@ -34,6 +34,8 @@ public class XxlJobConfig {
     @Value("${xxl.job.executor.logpath}")
     private String logpath;
 
+    @Value("${xxl.job.accessToken}")
+    private String accessToken;
 
     @Bean(initMethod = "start", destroyMethod = "destroy")
     public XxlJobExecutor xxlJobExecutor() {
@@ -44,6 +46,7 @@ public class XxlJobConfig {
         xxlJobExecutor.setAppName(appname);
         xxlJobExecutor.setAdminAddresses(addresses);
         xxlJobExecutor.setLogPath(logpath);
+        xxlJobExecutor.setAccessToken(accessToken);
         return xxlJobExecutor;
     }
 

+ 3 - 0
xxl-job-executor-springboot-example/src/main/resources/application.properties

@@ -15,3 +15,6 @@ xxl.job.executor.port=9998
 
 ### xxl-job log path
 xxl.job.executor.logpath=/data/applogs/xxl-job/jobhandler/
+
+### xxl-job, access token
+xxl.job.accessToken=