src/main/java/uw/task/util/LocalRateLimiter.java
public class LocalRateLimiter {

    private ConcurrentHashMap<String, RateLimiter> map = new ConcurrentHashMap<>();

    /**
     * 尝试获得限制允许状态。
     *
     * @param name
     * @return
     */
    public boolean tryAcquire(String name, int requests, int seconds, long waitTime, int permits) {
        if (requests == 0 || seconds == 0) {
            return true;
        }
        final double rate = (double) requests / (double) seconds;
        RateLimiter limiter = map.computeIfAbsent(name, key -> RateLimiter.create(rate));
        if (limiter != null) {
            //检查并修改
            if (limiter.getRate() != rate) {
                limiter.setRate(rate);
            }
            return limiter.tryAcquire(permits, waitTime, TimeUnit.SECONDS);
        } else {
            return true;
        }
    }

}
src/main/java/uw/task/TaskFactory.java
public class TaskFactory {

    private static final Logger log = LoggerFactory.getLogger(TaskFactory.class);

    /**
     * rabbitTemplate模板.
     */
    private RabbitTemplate rabbitTemplate;

    /**
     * 全局sequence序列，主要用于taskLog日志。
     */
    private GlobalSequenceManager globalSequenceManager;

    /**
     * 用于本地执行任务的taskConsumer。
     */
    private TaskRunnerContainer taskRunnerContainer;

    /**
     * rpc异步调用线程池
     */
    private ExecutorService taskRpcService = null;

    /**
     * 最大重试次数。
     */
    private static final int MAX_RETRY_TIMES = 10;


    public TaskFactory(TaskProperties taskProperties, RabbitTemplate rabbitTemplate,
                       TaskRunnerContainer taskRunnerContainer, GlobalSequenceManager globalSequenceManager) {
        this.rabbitTemplate = rabbitTemplate;
        this.taskRunnerContainer = taskRunnerContainer;
        this.globalSequenceManager = globalSequenceManager;
        taskRpcService = new ThreadPoolExecutor(taskProperties.getTaskRpcMinThreadNum(),
                taskProperties.getTaskRpcMaxThreadNum(), 20L, TimeUnit.SECONDS, new SynchronousQueue<>(),
                new ThreadFactoryBuilder().setDaemon(true).setNameFormat("TaskRpc-%d").build(), new ThreadPoolExecutor.CallerRunsPolicy());

    }

    /**
     * 把任务发送到队列中
     *
     * @param taskData 任务数据
     */
    public void sendToQueue(final TaskData<?, ?> taskData) {
        Message message = buildTaskQueueMessage(taskData);
        String queue = message.getMessageProperties().getConsumerQueue();
        //此处可能出现The channelMax limit is reached.报错，所以进行重试。
        for (int i = 0; i < MAX_RETRY_TIMES; i++) {
            try {
                if (i > 0) {
                    Thread.sleep(i * 500);
                }
                rabbitTemplate.send(queue, queue, message);
                return;
            } catch (Exception e) {
                log.error(e.getMessage(), e);
            }
        }
        throw new TaskRuntimeException("The channelMax limit is reached!");
    }

    /**
     * 构造Task消息对象，此方法用于提前构造TaskData。
     *
     * @param taskData
     * @return
     */
    private Message buildTaskQueueMessage(final TaskData taskData) {
        taskData.setId(globalSequenceManager.nextId("task_runner_log"));
        taskData.setQueueDate(new Date());
        taskData.setRunType(TaskData.RUN_TYPE_GLOBAL);
        MessageProperties messageProperties = new MessageProperties();
        messageProperties.setConsumerQueue(TaskMetaInfoManager.getFitQueue(taskData));
        Message msg = rabbitTemplate.getMessageConverter().toMessage(taskData, messageProperties);
        return msg;
    }

    /**
     * 同步执行任务，可能会导致阻塞。
     * 在调用的时候，尤其要注意，taskData对象不可改变！
     *
     * @param taskData 任务数据
     * @return
     */
    @SuppressWarnings("unchecked")
    public <TP, RD> TaskData<TP, RD> runTask(final TaskData<TP, RD> taskData) {
        taskData.setId(globalSequenceManager.nextId("task_runner_log"));
        taskData.setQueueDate(new Date());
        // 当自动RPC，并且本地有runner，而且target匹配的时候，运行在本地模式下。
        if (taskData.getRunType() == TaskData.RUN_TYPE_AUTO_RPC && TaskMetaInfoManager.checkRunnerRunLocal(taskData)) {
            // 启动本地运行模式。
            taskData.setRunType(TaskData.RUN_TYPE_LOCAL);
        }
        if (taskData.getRunType() == TaskData.RUN_TYPE_LOCAL) {
            taskRunnerContainer.process(taskData);
            return taskData;
        } else {
            taskData.setRunType(TaskData.RUN_TYPE_GLOBAL_RPC);
            //加入优先级信息。
            MessageProperties messageProperties = new MessageProperties();
            messageProperties.setPriority(10);
            messageProperties.setDeliveryMode(MessageDeliveryMode.NON_PERSISTENT);
            messageProperties.setExpiration("180000");
            Message message = rabbitTemplate.getMessageConverter().toMessage(taskData, messageProperties);
            // 全局运行模式
            String queue = TaskMetaInfoManager.getFitQueue(taskData);
            //此处可能出现The channelMax limit is reached.报错，所以进行重试。
            for (int i = 0; i < MAX_RETRY_TIMES; i++) {
                try {
                    if (i > 0) {
                        Thread.sleep(i * 500);
                    }
                    Message retMessage = rabbitTemplate.sendAndReceive(queue, queue, message);
                    return (TaskData<TP, RD>) rabbitTemplate.getMessageConverter().fromMessage(retMessage);
                } catch (Exception e) {
                    log.error(e.getMessage(), e);
                }
            }
            throw new TaskRuntimeException("The channelMax limit is reached!");
        }
    }

    /**
     * 同步执行任务，可能会导致阻塞。
     * 在调用的时候，尤其要注意，taskData对象不可改变！
     *
     * @param taskData 任务数据
     * @return
     */
    @SuppressWarnings("unchecked")
    public <TP, RD> TaskData<TP, RD> runTaskLocal(final TaskData<TP, RD> taskData) {
        taskData.setId(globalSequenceManager.nextId("task_runner_log"));
        taskData.setQueueDate(new Date());
        // 当自动RPC，并且本地有runner，而且target匹配的时候，运行在本地模式下。
        if (taskData.getRunType() == TaskData.RUN_TYPE_AUTO_RPC && TaskMetaInfoManager.checkRunnerRunLocal(taskData)) {
            // 启动本地运行模式。
            taskData.setRunType(TaskData.RUN_TYPE_LOCAL);
        }
        if (taskData.getRunType() == TaskData.RUN_TYPE_LOCAL) {
            taskRunnerContainer.process(taskData);
            return taskData;
        } else {
            throw new TaskRuntimeException(taskData.getClass().getName() + " is not a local task! ");
        }
    }

    /**
     * 远程运行任务，并返回future<TaskData<?,?>>。 如果需要获得数据，可以使用futrue.get()来获得。
     * 此方法要谨慎使用，因为task存在限速，大并发下可能会导致线程数超。
     * 在调用的时候，尤其要注意，taskData对象不可改变！
     *
     * @param taskData 任务数据
     * @return
     */
    @SuppressWarnings("unchecked")
    public <TP, RD> Future<TaskData<TP, RD>> runTaskAsync(final TaskData<TP, RD> taskData) {
        taskData.setId(globalSequenceManager.nextId("task_runner_log"));
        taskData.setQueueDate(new Date());

        // 当自动RPC，并且本地有runner，而且target匹配的时候，运行在本地模式下。
        if (taskData.getRunType() == TaskData.RUN_TYPE_AUTO_RPC && TaskMetaInfoManager.checkRunnerRunLocal(taskData)) {
            // 启动本地运行模式。
            taskData.setRunType(TaskData.RUN_TYPE_LOCAL);
        }
        if (taskData.getRunType() == TaskData.RUN_TYPE_LOCAL) {
            // 启动本地运行模式。
            return taskRpcService.submit(() -> {
                taskRunnerContainer.process(taskData);
                return taskData;
            });
        } else {
            // 全局运行模式
            taskData.setRunType(TaskData.RUN_TYPE_GLOBAL_RPC);
            //加入优先级信息。
            MessageProperties messageProperties = new MessageProperties();
            messageProperties.setPriority(10);
            messageProperties.setDeliveryMode(MessageDeliveryMode.NON_PERSISTENT);
            messageProperties.setExpiration("180000");
            Message message = rabbitTemplate.getMessageConverter().toMessage(taskData, messageProperties);
            String queue = TaskMetaInfoManager.getFitQueue(taskData);
            return taskRpcService.submit(() -> {
                //此处可能出现The channelMax limit is reached.报错，所以进行重试。
                for (int i = 0; i < MAX_RETRY_TIMES; i++) {
                    try {
                        if (i > 0) {
                            Thread.sleep(i * 500);
                        }
                        Message retMessage = rabbitTemplate.sendAndReceive(queue, queue, message);
                        return (TaskData<TP, RD>) rabbitTemplate.getMessageConverter().fromMessage(retMessage);
                    } catch (Exception e) {
                        log.error(e.getMessage(), e);
                    }
                }
                throw new TaskRuntimeException("The channelMax limit is reached!");
            });
        }
    }

    /**
     * 获得队列信息。
     *
     * @param queueName
     * @return 0 是消息数量 1 是消费者数量
     */
    public int[] getQueueInfo(String queueName) {
        AMQP.Queue.DeclareOk declareOk = this.rabbitTemplate.execute(new ChannelCallback<AMQP.Queue.DeclareOk>() {
            public AMQP.Queue.DeclareOk doInRabbit(Channel channel) throws Exception {
                return channel.queueDeclarePassive(queueName);
            }
        });
        return new int[]{declareOk.getMessageCount(), declareOk.getConsumerCount()};
    }

    /**
     * 清除队列。
     *
     * @param queueName
     * @return 被清除的队列数
     */
    public int purgeQueue(String queueName) {
        return this.rabbitTemplate.execute(channel -> {
            AMQP.Queue.PurgeOk queuePurged = channel.queuePurge(queueName);
            return queuePurged.getMessageCount();
        });
    }

}
src/main/java/uw/task/listener/RunnerTaskListener.java
public interface RunnerTaskListener {

    /**
     * 执行前的监听器。
     *
     * @param data
     */
    public void onPreExecute(TaskData data);

    /**
     * 执行后的监听器。
     *
     * @param data
     */
    public void onPostExecute(TaskData data);

}
src/main/java/uw/task/util/GlobalRateLimiter.java
public class GlobalRateLimiter {

    private static final Logger log = LoggerFactory.getLogger(GlobalRateLimiter.class);

    private static final String REDIS_PREFIX = "TaskRateLimit:";

    private final RedisTemplate<String, Long> redisTemplate;

    /**
     * LUA脚本。
     * 返回值为：可用请求数,等待毫秒数。
     */
    private static final RedisScript<Long> LUA_RATE_LIMIT = RedisScript.of(
            "local key = KEYS[1];\n" +
                    "local requests = tonumber(ARGV[1]);\n" +
                    "local millis = tonumber(ARGV[2])*1000;\n" +
                    "local permits = tonumber(ARGV[3]);\n" +
                    "local remainRequests=0;\n" +
                    "local waitMillis=0;\n" +
                    "local nowRate= redis.call('INCRBY', key,permits);\n" +
                    "if (nowRate==permits) then \n" +//如果是第一次执行，设置有效期保护。
                    "    redis.call('PEXPIRE',key,millis);\n" +
                    "end\n" +
                    "remainRequests = requests-nowRate;\n" +
                    "if (remainRequests<1) then \n" +//请求数超过限制
                    "    waitMillis = redis.call('PTTL',key);\n" +
                    "    if (waitMillis == -1) then \n" +
                    "        redis.call('PEXPIRE',key,millis);\n" +
                    "        waitMillis = millis;\n" +
                    "    end\n" +
                    "end \n" +
                    "return waitMillis", Long.class);


    public GlobalRateLimiter(final RedisConnectionFactory redisConnectionFactory) {
        redisTemplate = new RedisTemplate<String, Long>();
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new GenericToStringSerializer<Long>(Long.class));
        redisTemplate.setExposeConnection(true);
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        redisTemplate.afterPropertiesSet();
    }

    /**
     * 尝试可否获得授权。
     *
     * @param permits       申请访问次数
     * @return 如果未超限则返回0，-1为不确定时间，其他为需要等待的毫秒数
     */
    public long tryAcquire(String name, int requests, int seconds, int permits) {
        if (requests == 0 || seconds == 0) {
            return 0;
        }
        Long waitLimit = redisTemplate.execute(LUA_RATE_LIMIT, Collections.singletonList(REDIS_PREFIX + name), requests,seconds, permits);
        if (waitLimit==null)
            return 0;
        else
            return waitLimit;
    }

}
src/main/java/uw/task/exception/TaskPartnerException.java
public class TaskPartnerException extends Exception {

    /**
     * <code>serialVersionUID</code> 的注释
     */
    private static final long serialVersionUID = 8713460933603499992L;

    public TaskPartnerException() {
        super();
    }

    public TaskPartnerException(String msg) {
        super(msg);
    }

    public TaskPartnerException(Throwable nestedThrowable) {
        super(nestedThrowable);
    }

    public TaskPartnerException(String msg, Throwable nestedThrowable) {
        super(msg, nestedThrowable);
    }

}
src/main/java/uw/task/TaskData.java
public class TaskData<TP, RD> implements Serializable {

    /**
     * serialVersionUID
     */
    private static final long serialVersionUID = 1333167065535557828L;

    /**
     * 任务状态:未设置
     */
    public static final int STATE_UNKNOWN = 0;

    /**
     * 任务状态:成功
     */
    public static final int STATE_SUCCESS = 1;

    /**
     * 任务状态:程序错误
     */
    public static final int STATE_FAIL_PROGRAM = 2;

    /**
     * 任务状态:配置错误，如超过流量限制
     */
    public static final int STATE_FAIL_CONFIG = 3;

    /**
     * 任务状态:第三方接口错误
     */
    public static final int STATE_FAIL_PARTNER = 4;

    /**
     * 任务状态:数据错误
     */
    public static final int STATE_FAIL_DATA = 5;

    /**
     * 运行模式：本地运行
     */
    public static final int RUN_TYPE_LOCAL = 1;

    /**
     * 运行模式：全局运行
     */
    public static final int RUN_TYPE_GLOBAL = 3;

    /**
     * 运行模式：全局运行RPC返回结果
     */
    public static final int RUN_TYPE_GLOBAL_RPC = 5;

    /**
     * 运行模式：自动运行RPC返回结果，使用此模式，会自动选择本地还远程运行模式。
     */
    public static final int RUN_TYPE_AUTO_RPC = 6;

    /**
     * 自动重试[为了兼容,默认开启重试]
     */
    public static final int RETRY_TYPE_AUTO = 0;

    /**
     * 用户手工重试
     */
    public static final int RETRY_TYPE_MANUAL = 1;

    /**
     * id，此序列值由框架自动生成，无需手工设置。
     */
    private long id;

    /**
     * 关联TAG，由调用方设定，用于第三方统计信息。
     */
    private String refTag;

    /**
     * 关联id，由调用方根据需要设置，用于第三方统计信息。
     */
    private long refId;

    /**
     * 关联子id，由调用方根据需要设置，用于第三方统计信息。
     */
    private long refSubId;

    /**
     * 关联对象，此对象不存入数据库，但可以通过Listener来访问。
     */
    @JsonIgnore
    private Object refObject;

    /**
     * 流量限制TAG。
     */
    private String rateLimitTag;

    /**
     * 需要执行的类名，此数值必须由调用方设置。
     */
    private String taskClass = "";

    /**
     * 任务标签，用于细分任务队列，支持多实例运行。
     */
    private String taskTag = "";

    /**
     * 任务延迟毫秒数。一般这个时间不宜太长，大多数情况下不要超过60秒。
     */
    private long taskDelay;

    /**
     * 执行参数，此数值必须有调用方设置。
     */
    private TP taskParam;

    /**
     * 任务运行类型，默认为自动RPC，根据情况选择本地还是远程运行。
     */
    private int runType = RUN_TYPE_AUTO_RPC;

    /**
     * 重试类型
     */
    private int retryType;

    /**
     * 指定运行目标。
     */
    private String runTarget = "";

    /**
     * 任务运行时主机IP，此信息由框架自动设置。
     */
    private String hostIp;

    /**
     * 任务运行时主机ID（可能为docker的ContainerID），此信息由框架自动设置。
     */
    private String hostId;

    /**
     * 进入队列时间，此信息由框架自动设置。
     */
    private Date queueDate;

    /**
     * 开始消费时间，此信息由框架自动设置。
     */
    private Date consumeDate;

    /**
     * 开始运行时间，此信息由框架自动设置。
     */
    private Date runDate;

    /**
     * 运行结束日期，此信息由框架自动设置。
     */
    private Date finishDate;

    /**
     * 执行信息，用于存储框架自动设置。
     */
    private RD resultData;

    /**
     * 出错信息
     */
    private String errorInfo;

    /**
     * 已经执行的次数，此信息由框架自动设置。
     */
    private int ranTimes;

    /**
     * 执行状态，此信息由框架根据异常自动设置。
     */
    private int state;

    /**
     * @return the id
     */
    public long getId() {
        return id;
    }

    /**
     * @param id the id to set
     */
    public void setId(long id) {
        this.id = id;
    }

    /**
     * @return the refId
     */
    public long getRefId() {
        return refId;
    }

    /**
     * @param refId the refId to set
     */
    public void setRefId(long refId) {
        this.refId = refId;
    }

    /**
	 * @return the refSubId
	 */
	public long getRefSubId() {
		return refSubId;
	}

	/**
	 * @param refSubId the refSubId to set
	 */
	public void setRefSubId(long refSubId) {
		this.refSubId = refSubId;
	}

	/**
	 * @return the refTag
	 */
	public String getRefTag() {
		return refTag;
	}

	/**
	 * @param refTag the refTag to set
	 */
	public void setRefTag(String refTag) {
		this.refTag = refTag;
	}

	/**
	 * @return the rateLimitTag
	 */
	public String getRateLimitTag() {
		return rateLimitTag;
	}

	/**
	 * @param rateLimitTag the rateLimitTag to set
	 */
	public void setRateLimitTag(String rateLimitTag) {
		this.rateLimitTag = rateLimitTag;
	}

	/**
	 * @return the refObject
	 */
	public Object getRefObject() {
		return refObject;
	}

    /**
     * @param refObject the refObject to set
     */
    public void setRefObject(Object refObject) {
        this.refObject = refObject;
    }

    /**
     * @return the taskClass
     */
    public String getTaskClass() {
        return taskClass;
    }

    /**
     * @param taskClass the taskClass to set
     */
    public void setTaskClass(String taskClass) {
        this.taskClass = taskClass;
    }

    /**
	 * @return the taskTag
	 */
	public String getTaskTag() {
		return taskTag;
	}

	public long getTaskDelay() {
		return taskDelay;
	}

	public void setTaskDelay(long taskDelay) {
		this.taskDelay = taskDelay;
	}

	/**
	 * @param taskTag the taskTag to set
	 */
	public void setTaskTag(String taskTag) {
		this.taskTag = taskTag;
	}

	/**
     * @return the taskParam
     */
    public TP getTaskParam() {
        return taskParam;
    }

    /**
     * @param taskParam the taskParam to set
     */
    public void setTaskParam(TP taskParam) {
        this.taskParam = taskParam;
    }

    /**
     * @return the runType
     */
    public int getRunType() {
        return runType;
    }

    /**
     * @param runType the runType to set
     */
    public void setRunType(int runType) {
        this.runType = runType;
    }

    public int getRetryType() {
        return retryType;
    }

    public void setRetryType(int retryType) {
        this.retryType = retryType;
    }

    /**
     * @return the runTarget
     */
    public String getRunTarget() {
        return runTarget;
    }

    /**
     * @param runTarget the runTarget to set
     */
    public void setRunTarget(String runTarget) {
        this.runTarget = runTarget;
    }

    /**
     * @return the hostIp
     */
    public String getHostIp() {
        return hostIp;
    }

    /**
     * @param hostIp the hostIp to set
     */
    public void setHostIp(String hostIp) {
        this.hostIp = hostIp;
    }

    /**
     * @return the hostId
     */
    public String getHostId() {
        return hostId;
    }

    /**
     * @param hostId the hostId to set
     */
    public void setHostId(String hostId) {
        this.hostId = hostId;
    }

    /**
     * @return the queueDate
     */
    public Date getQueueDate() {
        return queueDate;
    }

    /**
     * @param queueDate the queueDate to set
     */
    public void setQueueDate(Date queueDate) {
        this.queueDate = queueDate;
    }

    /**
     * @return the consumeDate
     */
    public Date getConsumeDate() {
        return consumeDate;
    }

    /**
     * @param consumeDate the consumeDate to set
     */
    public void setConsumeDate(Date consumeDate) {
        this.consumeDate = consumeDate;
    }

    /**
     * @return the runDate
     */
    public Date getRunDate() {
        return runDate;
    }

    /**
     * @param runDate the runDate to set
     */
    public void setRunDate(Date runDate) {
        this.runDate = runDate;
    }

    /**
     * @return the finishDate
     */
    public Date getFinishDate() {
        return finishDate;
    }

    /**
     * @param finishDate the finishDate to set
     */
    public void setFinishDate(Date finishDate) {
        this.finishDate = finishDate;
    }

    /**
     * @return the resultData
     */
    public RD getResultData() {
        return resultData;
    }

    /**
     * @param resultData the resultData to set
     */
    public void setResultData(RD resultData) {
        this.resultData = resultData;
    }

    /**
     * @return the errorInfo
     */
    public String getErrorInfo() {
        return errorInfo;
    }

    /**
     * @param errorInfo the errorInfo to set
     */
    public void setErrorInfo(String errorInfo) {
        this.errorInfo = errorInfo;
    }

    /**
     * @return the ranTimes
     */
    public int getRanTimes() {
        return ranTimes;
    }

    /**
     * @param ranTimes the ranTimes to set
     */
    public void setRanTimes(int ranTimes) {
        this.ranTimes = ranTimes;
    }

    /**
     * @return the status
     */
    public int getState() {
        return state;
    }

    /**
     * @param status the status to set
     */
    public void setState(int status) {
        this.state = status;
    }

}
src/main/java/uw/task/TaskRunner.java
public abstract class TaskRunner<TP, RD> {

    /**
     * 执行任务。
     * 业务层面的异常请根据实际情况手动Throw TaskException:
     * 目前支持的异常:
     * 1. TaskDataException 任务数据异常
     * 2. TaskPartnerException 任务合作方异常
     *
     * @param taskData 数据
     * @throws Exception 异常
     * @return 指定的返回对象
     */
    public abstract RD runTask(TaskData<TP, RD> taskData) throws Exception;

    /**
     * 初始化配置信息
     *
     * @return TaskRunnerConfig配置
     */
    public abstract TaskRunnerConfig initConfig();

    /**
     * 初始化联系人信息
     *
     * @return TaskContact联系人信息
     */
    public abstract TaskContact initContact();
}
src/main/java/uw/task/conf/TaskMetaInfoManager.java
public class TaskMetaInfoManager {

	/**
	 * 运行主机配置
	 */
	static List<String> targetConfig = null;

	/**
	 * Runner任务实例缓存。
	 */
	@SuppressWarnings("rawtypes")
	static Map<String, TaskRunner> runnerMap = new HashMap<>();

	/**
	 * Cron任务实例缓存。
	 */
	static Map<String, TaskCroner> cronerMap = new HashMap<>();

	/**
	 * Runner任务配置缓存
	 */
	static ConcurrentHashMap<String, TaskRunnerConfig> runnerConfigMap = new ConcurrentHashMap<>();

	/**
	 * Cron任务配置缓存。
	 */
	static ConcurrentHashMap<String, TaskCronerConfig> cronerConfigMap = new ConcurrentHashMap<>();

	/**
	 * 获得任务运行实例。
	 *
	 * @param taskClass
	 * @return
	 */
	public static TaskRunner<?, ?> getRunner(String taskClass) {
		return runnerMap.get(taskClass);
	}

	/**
	 * 检查一个runner是否可以在本地运行。
	 * 
	 * @param taskData
	 * @return
	 */
	public static boolean checkRunnerRunLocal(TaskData<?, ?> taskData) {
		return runnerMap.containsKey(taskData.getTaskClass());
	}

	/**
	 * 根据服务器端Queue列表，返回合适的key。
	 * 
	 * @return
	 */
	public static String getFitQueue(TaskData<?, ?> data) {
		StringBuilder sb = new StringBuilder(100);
		sb.append(data.getTaskClass()).append("#");
		if (data.getTaskTag() != null && data.getTaskTag().length() > 0) {
			sb.append(data.getTaskTag());
		}
		sb.append("$");
		if (data.getRunTarget() != null && data.getRunTarget().length() > 0) {
			sb.append(data.getRunTarget());
		}
		String all = sb.toString();
		if (runnerConfigMap.containsKey(all)) {
			return all;
		}
        // 检测去除TAG的情况
        if (!all.contains("#$")) {
            String test = all.substring(0, all.indexOf('#') + 1) + all.substring(all.lastIndexOf('$'), all.length());
            if (runnerConfigMap.containsKey(test)) {
                return test;
            }
        }
		// 检测去除目标的情况
		if (!all.endsWith("$")) {
			String test = all.substring(0, all.lastIndexOf('$') + 1);
			if (runnerConfigMap.containsKey(test)) {
				return test;
			}
		}
		// 两个都去除的情况
		if (!all.endsWith("#$")) {
			String test = data.getTaskClass() + "#$";
			if (runnerConfigMap.containsKey(test)) {
				return test;
			}
		}
		// 最后都没匹配到，返回原始数据
		return all;
	}

	/**
	 * 获得任务配置
	 *
	 * @param data
	 * @return
	 */
	public static TaskRunnerConfig getRunnerConfig(TaskData<?, ?> data) {
		TaskRunnerConfig config = null;
		StringBuilder sb = new StringBuilder(100);
		sb.append(data.getTaskClass()).append("#");
		if (data.getTaskTag() != null && data.getTaskTag().length() > 0) {
			sb.append(data.getTaskTag());
		}
		sb.append("$");
		if (data.getRunTarget() != null && data.getRunTarget().length() > 0) {
			sb.append(data.getRunTarget());
		}
		String all = sb.toString();
		config = runnerConfigMap.get(all);
		if (config != null) {
			return config;
		}
        // 检测去除TAG的情况
        if (!all.contains("#$")) {
            String test = all.substring(0, all.indexOf('#') + 1) + all.substring(all.lastIndexOf('$'), all.length());
            config = runnerConfigMap.get(test);
            if (config != null) {
                return config;
            }
        }
		// 检测去除目标的情况
		if (!all.endsWith("$")) {
			String test = all.substring(0, all.lastIndexOf('$') + 1);
			config = runnerConfigMap.get(test);
			if (config != null) {
				return config;
			}
		}
		// 两个都去除的情况
		if (!all.endsWith("#$")) {
			String test = data.getTaskClass() + "#$";
			config = runnerConfigMap.get(test);
			if (config != null) {
				return config;
			}
		}
		throw new RuntimeException("找不到任务配置: taskClass = " + data.getTaskClass());
	}

	/**
	 * 更新系统队列表。
	 * 
	 * @param config
	 */
	static void updateSysQueue(final TaskRunnerConfig config) {
		String key = getRunnerConfigKey(config);
		// 检测是否老的TaskRunnerConfig是否是本地的完整配置，如果是，则不管。
		TaskRunnerConfig old = runnerConfigMap.get(key);
		if (old == null || (old != null && old.getCreateDate() == null)) {
			if (config.getState() < 1) {
				runnerConfigMap.remove(key);
			} else {
				runnerConfigMap.put(key, config);
			}
		}
	}

	/**
	 * 获得croner配置键。 使用taskClass#Id$target来配置
	 * 
	 * @return
	 */
	public static String getCronerConfigKey(TaskCronerConfig config) {
		StringBuilder sb = new StringBuilder(100);
		sb.append(config.getTaskClass()).append("#");
		if (config.getTaskParam() != null && config.getTaskParam().length() > 0) {
			sb.append(config.getId());
		}
		sb.append("$");
		if (config.getRunTarget() != null && config.getRunTarget().length() > 0) {
			sb.append(config.getRunTarget());
		}
		return sb.toString();
	}

	/**
	 * 获得Runner配置结合Host。
	 * 
	 * @return
	 */
	public static String getRunnerConfigKey(TaskRunnerConfig config) {
		StringBuilder sb = new StringBuilder(100);
		sb.append(config.getTaskClass()).append("#");
		if (config.getTaskTag() != null && config.getTaskTag().length() > 0) {
			sb.append(config.getTaskTag());
		}
		sb.append("$");
		if (config.getRunTarget() != null && config.getRunTarget().length() > 0) {
			sb.append(config.getRunTarget());
		}
		return sb.toString();
	}

    /**
     * 获得RunnerLog配置KEY
     *
     * @return
     */
    public static String getRunnerLogKey(TaskData<?,?> log) {
        StringBuilder sb = new StringBuilder(100);
        sb.append(log.getTaskClass()).append("#");
        if (log.getTaskTag() != null && log.getTaskTag().length() > 0) {
            sb.append(log.getTaskTag());
        }
        sb.append("$");
        if (log.getRunTarget() != null && log.getRunTarget().length() > 0) {
            sb.append(log.getRunTarget());
        }
        return sb.toString();
    }

    /**
     * 获得CronerLog配置KEY
     *
     * @return
     */
    public static String getCronerLogKey(TaskCronerLog log) {
        StringBuilder sb = new StringBuilder(100);
        sb.append(log.getTaskClass()).append("#");
        if (log.getTaskParam() != null && log.getTaskParam().length()>0){
            sb.append(log.getTaskParam());
        }
        sb.append("$");
        if (log.getRunTarget() != null && log.getRunTarget().length() > 0) {
            sb.append(log.getRunTarget());
        }
        return sb.toString();
    }
}
src/main/java/uw/task/api/TaskAPI.java
public class TaskAPI {

    private static final Logger log = LoggerFactory.getLogger(TaskAPI.class);

    /**
     * Task配置文件
     */
    private TaskProperties taskProperties;

    /**
     * Rest模板类
     */
    private RestTemplate restTemplate;

    /**
     * 日志客户端。
     */
    private LogClient logClient = null;

    /**
     * 本机的外网IP
     */
    private String hostIp = "";

    public TaskAPI(final TaskProperties taskProperties, final RestTemplate restTemplate,
                   final LogClient logClient) {
        this.taskProperties = taskProperties;
        this.restTemplate = restTemplate;
        this.logClient = logClient;
    }

    /**
     * @return the hostIp
     */
    public String getHostIp() {
        return hostIp;
    }

    /**
     * 更新当前主机目标配置。
     *
     * @return
     */
    public List<String> getServerTargetConfig() {
        List<String> targetConfig = null;
        // 判断是否是私有模式。
        boolean privacyMode = taskProperties.isPrivacyMode();
        try {
            String[] data = restTemplate.getForObject(
                    taskProperties.getTaskCenterHost() + "/taskapi/target/config?targetType={targetType}", String[].class,
                    privacyMode ? 1 : 0);
            targetConfig = Arrays.asList(data);
        } catch (Exception e) {
            log.error("TaskAPI.getHostConfig()服务端Target配置拉取异常:{}", e.getMessage());
        }
        if (targetConfig == null || targetConfig.size() == 0) {
            if (log.isWarnEnabled()) {
                log.warn("获得主机Target服务端配置失败，启用默认配置项!");
            }
            targetConfig = new ArrayList<>();
            if (!privacyMode) {
                targetConfig.add("");
            }
        }
        return targetConfig;
    }

    /**
     * 更新当前主机状态，返回主机IP地址。
     *
     * @return 主机IP地址
     */
    public String updateHostStatus() {
        String ip = "";
        TaskHostStatus taskHostStatus = new TaskHostStatus();
        taskHostStatus.setHostId(taskProperties.getHostId());
        taskHostStatus.setTaskProject(taskProperties.getProject());
        try {
            ip = restTemplate.postForObject(taskProperties.getTaskCenterHost() + "/taskapi/host/status", taskHostStatus,
                    String.class);
            hostIp = ip;
        } catch (Exception e) {
            log.error("TaskAPI.updateHostStatus()服务端主机状态更新异常:{}", e.getMessage());
        }
        return ip;
    }

    /**
     * 初始化CronerConfig。
     *
     * @param config
     */
    public TaskCronerConfig initTaskCronerConfig(TaskCronerConfig config) {
        try {
            config = restTemplate.postForObject(taskProperties.getTaskCenterHost() + "/taskapi/croner/config", config,
                    TaskCronerConfig.class);
        } catch (Exception e) {
            log.error("TaskAPI.initTaskCronerConfig上传Croner配置到服务端异常:{}", e.getMessage());
        }
        return config;
    }

    /**
     * 初始化RunnerConfig
     *
     * @param config
     */
    public TaskRunnerConfig initTaskRunnerConfig(TaskRunnerConfig config) {
        try {
            config = restTemplate.postForObject(taskProperties.getTaskCenterHost() + "/taskapi/runner/config", config,
                    TaskRunnerConfig.class);
        } catch (Exception e) {
            log.error("TaskAPI.initTaskRunnerConfig上传Runner配置到服务端异常:{}", e.getMessage());
        }
        return config;

    }

    /**
     * 初始化联系人信息。
     *
     * @param contact
     */
    public void initTaskContact(TaskContact contact) {
        try {
            restTemplate.postForLocation(taskProperties.getTaskCenterHost() + "/taskapi/contact", contact);
        } catch (Exception e) {
            log.error("TaskAPI.initTaskContact上传联系人信息到服务端异常:{}", e.getMessage());
        }
    }

    /**
     * 根据更新时间获得变化的TaskRunner队列列表。
     *
     * @param lastUpdateTime 最后更新时间
     * @return
     */
    public List<TaskRunnerConfig> getTaskRunnerQueueList(long lastUpdateTime) {
        List<TaskRunnerConfig> list = null;
        try {
            TaskRunnerConfig[] data = restTemplate.getForObject(
                    taskProperties.getTaskCenterHost() + "/taskapi/runner/queue?lastUpdateTime={lastUpdateTime}",
                    TaskRunnerConfig[].class, lastUpdateTime);
            list = Arrays.asList(data);
        } catch (Exception e) {
            log.error("TaskAPI.getTaskRunnerQueueList()服务端主机状态更新异常:{}", e.getMessage());
        }

        return list;
    }

    /**
     * 根据包名前缀获得TaskRunner配置列表。
     *
     * @param taskPackage
     * @param lastUpdateTime 最后更新时间
     * @return
     */
    public List<TaskRunnerConfig> getTaskRunnerConfigList(String taskPackage, long lastUpdateTime) {
        List<TaskRunnerConfig> list = null;
        try {
            TaskRunnerConfig[] data = restTemplate.getForObject(
                    taskProperties.getTaskCenterHost()
                            + "/taskapi/runner/config?taskPackage={taskPackage}&lastUpdateTime={lastUpdateTime}",
                    TaskRunnerConfig[].class, taskPackage, lastUpdateTime);
            list = Arrays.asList(data);
        } catch (Exception e) {
            log.error("TaskAPI.getTaskRunnerConfigList()服务端主机状态更新异常:{}", e.getMessage());
        }

        return list;
    }

    /**
     * 根据包名前缀获得TaskCroner配置列表。
     *
     * @param taskPackage
     * @param lastUpdateTime 最后更新时间
     * @return
     */
    public List<TaskCronerConfig> getTaskCronerConfigList(String taskPackage, long lastUpdateTime) {
        List<TaskCronerConfig> list = null;
        try {
            TaskCronerConfig[] data = restTemplate.getForObject(
                    taskProperties.getTaskCenterHost()
                            + "/taskapi/croner/config?taskPackage={taskPackage}&lastUpdateTime={lastUpdateTime}",
                    TaskCronerConfig[].class, taskPackage, lastUpdateTime);
            list = Arrays.asList(data);
        } catch (Exception e) {
            log.error("TaskAPI.getTaskCronerConfigList()服务端主机状态更新异常:{}", e.getMessage());
        }

        return list;
    }

    /**
     * 发送Runner任务日志。
     *
     * @param log
     */
    public void sendTaskRunnerLog(TaskRunnerLog log) {
        logClient.log(log);
    }

    /**
     * 发送CronLog日志
     *
     * @param configId      配置Id,方便更新下一次执行时间
     * @param taskCronerLog 日志对象
     */
    public void sendTaskCronerLog(long configId, TaskCronerLog taskCronerLog) {
        try {
            restTemplate.getForObject(
                    taskProperties.getTaskCenterHost()
                            + "/taskapi/croner/tick?id={id}&nextDate={nextDate}",
                    Integer.class, configId, taskCronerLog.getNextDate().getTime());
        } catch (Exception e) {
            log.error("TaskAPI.cornerTick()服务端主机状态更新异常: " + e.getMessage(), e);
        }

        int logLevel = taskCronerLog.getLogLevel();
        int logLimitSize = taskCronerLog.getLogLimitSize();
        if (logLevel > TaskCronerConfig.TASK_LOG_TYPE_NONE) {
            switch (logLevel) {
                case TaskCronerConfig.TASK_LOG_TYPE_RECORD: {
                    taskCronerLog.setTaskParam(null);
                    taskCronerLog.setResultData(null);
                }
                break;
                case TaskCronerConfig.TASK_LOG_TYPE_RECORD_TASK_PARAM: {
                    String taskParam = taskCronerLog.getTaskParam();
                    if (logLimitSize > 0 && StringUtils.isNotBlank(taskParam) && taskParam.length() > logLimitSize) {
                        taskCronerLog.setTaskParam(taskParam.substring(0, logLimitSize));
                    }
                    taskCronerLog.setResultData(null);
                }
                break;
                case TaskCronerConfig.TASK_LOG_TYPE_RECORD_RESULT_DATA: {
                    String resultData = taskCronerLog.getResultData();
                    if (logLimitSize > 0 && StringUtils.isNotBlank(resultData) && resultData.length() > logLimitSize) {
                        taskCronerLog.setResultData(resultData.substring(0, logLimitSize));
                    }
                    taskCronerLog.setTaskParam(null);
                }
                break;
                case TaskCronerConfig.TASK_LOG_TYPE_RECORD_ALL: {
                    if (logLimitSize > 0) {
                        String taskParam = taskCronerLog.getTaskParam();
                        String resultData = taskCronerLog.getResultData();
                        if (StringUtils.isNotBlank(taskParam) && taskParam.length() > logLimitSize) {
                            taskCronerLog.setTaskParam(taskParam.substring(0, logLimitSize));
                        }
                        if (StringUtils.isNotBlank(resultData) && resultData.length() > logLimitSize) {
                            taskCronerLog.setResultData(resultData.substring(0, logLimitSize));
                        }
                    }
                }
                break;
            }
            logClient.log(taskCronerLog);
        }
    }
}
src/main/java/uw/task/exception/TaskDataException.java
public class TaskDataException extends Exception {

    /**
     * <code>serialVersionUID</code> 的注释
     */
    private static final long serialVersionUID = 8713460933603499992L;

    public TaskDataException() {
        super();
    }

    public TaskDataException(String msg) {
        super(msg);
    }

    public TaskDataException(Throwable nestedThrowable) {
        super(nestedThrowable);
    }

    public TaskDataException(String msg, Throwable nestedThrowable) {
        super(msg, nestedThrowable);
    }

}
src/main/java/uw/task/entity/TaskRunnerConfig.java
public class TaskRunnerConfig implements Serializable {

    private static final long serialVersionUID = 1L;

    /**
     * 限速类型：不限速
     */
    public static final int RATE_LIMIT_NONE = 0;

    /**
     * 限速类型：本地进程限速
     */
    public static final int RATE_LIMIT_LOCAL = 1;

    /**
     * 限速类型：本地TASK限速
     */
    public static final int RATE_LIMIT_LOCAL_TASK = 2;

    /**
     * 限速类型：本地TASK+TAG限速
     */
    public static final int RATE_LIMIT_LOCAL_TASK_TAG = 3;

    /**
     * 限速类型：全局主机HOST限速
     */
    public static final int RATE_LIMIT_GLOBAL_HOST = 4;

    /**
     * 限速类型：全局TAG限速
     */
    public static final int RATE_LIMIT_GLOBAL_TAG = 5;

    /**
     * 限速类型：全局TASK限速
     */
    public static final int RATE_LIMIT_GLOBAL_TASK = 6;

    /**
     * 限速类型：全局TAG+HOST限速
     */
    public static final int RATE_LIMIT_GLOBAL_TAG_HOST = 7;

    /**
     * 限速类型：全局TASK+IP限速
     */
    public static final int RATE_LIMIT_GLOBAL_TASK_HOST = 8;

    /**
     * 限速类型：全局TASK+TAG限速
     */
    public static final int RATE_LIMIT_GLOBAL_TASK_TAG = 9;

    /**
     * 限速类型：全局TASK+TAG+IP限速
     */
    public static final int RATE_LIMIT_GLOBAL_TASK_TAG_HOST = 10;

    /**
     * 什么都不记录
     */
    public static final int TASK_LOG_TYPE_NONE = -1;

    /**
     * 记录日志
     */
    public static final int TASK_LOG_TYPE_RECORD = 0;

    /**
     * 记录日志,含请求参数
     */
    public static final int TASK_LOG_TYPE_RECORD_TASK_PARAM = 1;

    /**
     * 记录日志,含返回参数
     */
    public static final int TASK_LOG_TYPE_RECORD_RESULT_DATA = 2;

    /**
     * 记录全部日志
     */
    public static final int TASK_LOG_TYPE_RECORD_ALL = 3;

    private long id;

    /**
     * 任务名称
     */
    private String taskName;

    /**
     * 任务描述
     */
    private String taskDesc;

    /**
     * 执行类信息
     */
    private String taskClass;

    /**
     * 执行类TAG，可能用于区分子任务
     */
    private String taskTag;

    /**
     * 消费者的数量
     */
    private int consumerNum = 1;

    /**
     * 预取任务数。
     */
    private int prefetchNum = 1;

    /**
     * 详见流量限制类型说明。
     */
    private int rateLimitType = RATE_LIMIT_NONE;

    /**
     * 流量限定数值，默认为10次
     */
    private int rateLimitValue = 10;

    /**
     * 流量限定时间(S)，默认为1秒
     */
    private int rateLimitTime = 1;

    /**
     * 当发生流量限制时，等待的秒数，默认300秒
     */
    private int rateLimitWait = 30;

    /**
     * 超过流量限制重试次数，默认不在重试，放弃任务。
     */
    private int retryTimesByOverrated = 0;

    /**
     * 对方接口错误重试次数，默认不再重试，放弃任务。
     */
    private int retryTimesByPartner = 0;

    /**
     * 运行目标，默认不指定
     */
    private String runTarget = "";

    /**
     * 失败率
     */
    private int failRate;

    /**
     * 接口失败率
     */
    private int failPartnerRate;

    /**
     * 程序失败率
     */
    private int failProgramRate;

    /**
     * 配置失败率
     */
    private int failConfigRate;

    /**
     * 数据失败率
     */
    private int failDataRate;

    /**
     * 队列等待超时
     */
    private int queueTimeout;

    /**
     * 等待超时
     */
    private int waitTimeout;

    /**
     * 运行超时
     */
    private int runTimeout;

    /**
     * 创建日期。
     */
    private Date createDate;

    /**
     * 修改日期。
     */
    private Date modifyDate;

    /**
     * 状态值
     */
    private int state = 1;

    /**
     * 详见日志类型说明
     */
    private int logLevel = TASK_LOG_TYPE_RECORD;

    /**
     * 日志字符串字段大小限制: 0 表示无限制
     */
    private int logLimitSize = 0;

    public TaskRunnerConfig() {
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getTaskName() {
        return taskName;
    }

    public void setTaskName(String taskName) {
        this.taskName = taskName;
    }

    public String getTaskDesc() {
        return taskDesc;
    }

    public void setTaskDesc(String taskDesc) {
        this.taskDesc = taskDesc;
    }

    public String getTaskClass() {
        return taskClass;
    }

    public void setTaskClass(String taskClass) {
        this.taskClass = taskClass;
    }

    public String getTaskTag() {
        return taskTag;
    }

    public void setTaskTag(String taskTag) {
        this.taskTag = taskTag;
    }

    public int getConsumerNum() {
        return consumerNum;
    }

    public void setConsumerNum(int consumerNum) {
        this.consumerNum = consumerNum;
    }

    public int getPrefetchNum() {
        return prefetchNum;
    }

    public void setPrefetchNum(int prefetchNum) {
        this.prefetchNum = prefetchNum;
    }

    public int getRateLimitType() {
        return rateLimitType;
    }

    public void setRateLimitType(int rateLimitType) {
        this.rateLimitType = rateLimitType;
    }

    public int getRateLimitValue() {
        return rateLimitValue;
    }

    public void setRateLimitValue(int rateLimitValue) {
        this.rateLimitValue = rateLimitValue;
    }

    public int getRateLimitTime() {
        return rateLimitTime;
    }

    public void setRateLimitTime(int rateLimitTime) {
        this.rateLimitTime = rateLimitTime;
    }

    public int getRateLimitWait() {
        return rateLimitWait;
    }

    public void setRateLimitWait(int rateLimitWait) {
        this.rateLimitWait = rateLimitWait;
    }

    public int getRetryTimesByOverrated() {
        return retryTimesByOverrated;
    }

    public void setRetryTimesByOverrated(int retryTimesByOverrated) {
        this.retryTimesByOverrated = retryTimesByOverrated;
    }

    public int getRetryTimesByPartner() {
        return retryTimesByPartner;
    }

    public void setRetryTimesByPartner(int retryTimesByPartner) {
        this.retryTimesByPartner = retryTimesByPartner;
    }

    public String getRunTarget() {
        return runTarget;
    }

    public void setRunTarget(String runTarget) {
        this.runTarget = runTarget;
    }

    public int getFailRate() {
        return failRate;
    }

    public void setFailRate(int failRate) {
        this.failRate = failRate;
    }

    public int getFailPartnerRate() {
        return failPartnerRate;
    }

    public void setFailPartnerRate(int failPartnerRate) {
        this.failPartnerRate = failPartnerRate;
    }

    public int getFailProgramRate() {
        return failProgramRate;
    }

    public void setFailProgramRate(int failProgramRate) {
        this.failProgramRate = failProgramRate;
    }

    public int getFailConfigRate() {
        return failConfigRate;
    }

    public void setFailConfigRate(int failConfigRate) {
        this.failConfigRate = failConfigRate;
    }

    public int getFailDataRate() {
        return failDataRate;
    }

    public void setFailDataRate(int failDataRate) {
        this.failDataRate = failDataRate;
    }

    public int getQueueTimeout() {
        return queueTimeout;
    }

    public void setQueueTimeout(int queueTimeout) {
        this.queueTimeout = queueTimeout;
    }

    public int getWaitTimeout() {
        return waitTimeout;
    }

    public void setWaitTimeout(int waitTimeout) {
        this.waitTimeout = waitTimeout;
    }

    public int getRunTimeout() {
        return runTimeout;
    }

    public void setRunTimeout(int runTimeout) {
        this.runTimeout = runTimeout;
    }

    public Date getCreateDate() {
        return createDate;
    }

    public void setCreateDate(Date createDate) {
        this.createDate = createDate;
    }

    public Date getModifyDate() {
        return modifyDate;
    }

    public void setModifyDate(Date modifyDate) {
        this.modifyDate = modifyDate;
    }

    public int getState() {
        return state;
    }

    public void setState(int state) {
        this.state = state;
    }

    public int getLogLevel() {
        return logLevel;
    }

    public void setLogLevel(int logLevel) {
        this.logLevel = logLevel;
    }

    public int getLogLimitSize() {
        return logLimitSize;
    }

    public void setLogLimitSize(int logLimitSize) {
        this.logLimitSize = logLimitSize;
    }
}
src/main/java/uw/task/util/MiscUtils.java
public class MiscUtils {

    /**
     * taskData的copy器。
     */
    private static BeanCopier beanCopier = BeanCopier.create(TaskData.class, TaskData.class, false);

    /**
     * copy taskData对象。
     *
     * @param srcData
     * @param dstData
     */
    public static void copyTaskData(TaskData srcData, TaskData dstData) {
        beanCopier.copy(srcData, dstData, null);
    }

    /**
     * 打印异常信息，屏蔽掉spring自己的堆栈输出。
     *
     * @param e 需要打印的异常信息
     * @return
     */
    public static String exceptionToString(Throwable e) {
        StringBuilder sb = new StringBuilder();
        sb.append(e.toString()).append("\n");

        StackTraceElement[] trace = e.getStackTrace();
        for (StackTraceElement traceElement : trace) {
            if (traceElement.getClassName().startsWith("org.spring")) {
                continue;
            }
            if (traceElement.getClassName().startsWith("sun.")) {
                continue;
            }
            sb.append("\tat ").append(traceElement).append("\n");
        }
        Throwable ourCause = e.getCause();
        if (ourCause != null) {
            sb.append("CAUSE BY").append(ourCause.toString()).append("\n");
            trace = ourCause.getStackTrace();
            for (StackTraceElement traceElement : trace) {
                if (traceElement.getClassName().startsWith("org.spring")) {
                    continue;
                }
                if (traceElement.getClassName().startsWith("sun.")) {
                    continue;
                }
                sb.append("\tat ").append(traceElement).append("\n");
            }
        }
        return sb.toString();
    }

}
src/main/java/uw/task/TaskListenerManager.java
public class TaskListenerManager {

	/**
	 * runner监听器列表。
	 */
    private ArrayList<RunnerTaskListener> runnerListenerList = new ArrayList<>();

    /**
     * croner监听器列表。
     */
    private ArrayList<CronerTaskListener> cronerListenerList = new ArrayList<>();

    /**
     * 加入一个RunnerListener。
     *
     * @param listener
     */
    public void addRunnerListener(RunnerTaskListener listener) {
        runnerListenerList.add(listener);
    }

    /**
     * 加入一个RunnerListener.
     *
     * @param listener
     */
    public void addCronerListener(CronerTaskListener listener) {
        cronerListenerList.add(listener);
    }

    /**
     * 清除RunnerListener列表
     */
    public void clearRunnerListener() {
        runnerListenerList.clear();
    }

    /**
     * 清除RunnerListener列表
     */
    public void clearCronerListener() {
        cronerListenerList.clear();
    }

    /**
     * 获得Runner Listener列表。
     *
     * @return
     */
    public ArrayList<RunnerTaskListener> getRunnerListenerList() {
        return runnerListenerList;
    }

    /**
     * 获得Croner Listener列表。
     *
     * @return
     */
    public ArrayList<CronerTaskListener> getCronerListenerList() {
        return cronerListenerList;
    }

}
src/main/java/uw/task/entity/TaskRunnerLog.java
@JsonIgnoreProperties({"taskData"})
public class TaskRunnerLog extends LogBaseVo {

    private static final Logger logger = LoggerFactory.getLogger(TaskRunnerLog.class);

    private TaskData taskData;

    /**
     * logLimitSize。
     */
    private int logLimitSize;

    public TaskRunnerLog(TaskData taskData) {
        this.taskData = taskData;
    }

    public TaskData getTaskData() {
        return taskData;
    }

    /**
     * @return the id
     */
    public long getId() {
        return taskData.getId();
    }

    /**
     * @return the refId
     */
    public long getRefId() {
        return taskData.getRefId();
    }

    /**
     * @return the refSubId
     */
    public long getRefSubId() {
        return taskData.getRefSubId();
    }

    /**
     * @return the refTag
     */
    public String getRefTag() {
        return taskData.getRefTag();
    }

    /**
     * @return the rateLimitTag
     */
    public String getRateLimitTag() {
        return taskData.getRateLimitTag();
    }

    /**
     * @return the taskClass
     */
    public String getTaskClass() {
        return taskData.getTaskClass();
    }

    /**
     * @return the taskTag
     */
    public String getTaskTag() {
        return taskData.getTaskTag();
    }

    public long getTaskDelay() {
        return taskData.getTaskDelay();
    }

    /**
     * @return the taskParam
     */
    public String getTaskParam() {
        Object value = taskData.getTaskParam();
        if (value != null) {
            // 报错了
            if (taskData.getState() != TaskData.STATE_SUCCESS || logLevel == TaskRunnerConfig.TASK_LOG_TYPE_RECORD_ALL ||
                    logLevel == TaskRunnerConfig.TASK_LOG_TYPE_RECORD_TASK_PARAM) {
                String data = null;
                try {
                    data = JsonMapper.MAPPER.writeValueAsString(value);
                } catch (Exception e) {
                    data = e.getMessage();
                    logger.error(e.getMessage(), e);
                }
                if (data != null) {
                    if (logLimitSize > 0 && data.length() > logLimitSize) {
                        data = data.substring(0, logLimitSize);
                    }
                    return data;
                }
            }
        }
        return null;
    }

    /**
     * @return the runType
     */
    public int getRunType() {
        return taskData.getRunType();
    }

    /**
     * @return the retryType
     */
    public int getRetryType() {
        return taskData.getRetryType();
    }

    /**
     * @return the runTarget
     */
    public String getRunTarget() {
        return taskData.getRunTarget();
    }

    /**
     * @return the hostIp
     */
    public String getHostIp() {
        return taskData.getHostIp();
    }

    /**
     * @return the hostId
     */
    public String getHostId() {
        return taskData.getHostId();
    }

    /**
     * @return the queueDate
     */
    public Date getQueueDate() {
        return taskData.getQueueDate();
    }

    /**
     * @return the consumeDate
     */
    public Date getConsumeDate() {
        return taskData.getConsumeDate();
    }

    /**
     * @return the runDate
     */
    public Date getRunDate() {
        return taskData.getRunDate();
    }

    /**
     * @return the finishDate
     */
    public Date getFinishDate() {
        return taskData.getFinishDate();
    }

    /**
     * @return the resultData
     */
    public String getResultData() {
        Object value = taskData.getResultData();
        if (value != null) {
            // 报错了
            if (taskData.getState() != TaskData.STATE_SUCCESS || logLevel == TaskRunnerConfig.TASK_LOG_TYPE_RECORD_ALL ||
                    logLevel == TaskRunnerConfig.TASK_LOG_TYPE_RECORD_RESULT_DATA) {
                String data = null;
                try {
                    data = JsonMapper.MAPPER.writeValueAsString(value);
                } catch (Exception e) {
                    data = e.getMessage();
                    logger.error(e.getMessage(), e);
                }
                if (data != null) {
                    if (logLimitSize > 0 && data.length() > logLimitSize) {
                        data = data.substring(0, logLimitSize);
                    }
                    return data;
                }
            }
        }
        return null;
    }

    /**
     * @return the errorInfo
     */
    public String getErrorInfo() {
        return taskData.getErrorInfo();
    }

    /**
     * @return the ranTimes
     */
    public int getRanTimes() {
        return taskData.getRanTimes();
    }

    /**
     * @return the status
     */
    public int getState() {
        return taskData.getState();
    }

    public int getLogLimitSize() {
        return logLimitSize;
    }

    public void setLogLimitSize(int logLimitSize) {
        this.logLimitSize = logLimitSize;
    }
}
src/main/java/uw/task/conf/TaskProperties.java
@ConfigurationProperties(prefix = "uw.task")
public class TaskProperties {

    /**
     * 是否启用uw-task服务注册和主机注册，默认不启用。
     *
     */
    private boolean enableTaskRegistry = false;
    /**
     * 任务名，必须设置为基础包名。
     */
    private String project;

    /**
     * 私有模式。不运行全局target任务。
     */
    private boolean privacyMode = false;

    /**
     * croner线程数，默认在3个，建议按照实际croner任务数量*70%。
     */
    private int cronerThreadNum = 5;

    /**
     * RPC最小线程数,用于执行RPC调用，如不使用rpc，建议设置为1，否则按照最大并发量*10%设置。
     */
    private int taskRpcMinThreadNum = 1;

    /**
     * RPC最大线程数,用于执行RPC调用，超过此线程数，将会导致阻塞。
     */
    private int taskRpcMaxThreadNum = 100;

    /**
     * 队列任务重试延时毫秒数，默认2秒
     */
    private long taskQueueRetryDelay = 2000;

    /**
     *  rpc任务重试延时毫秒数，默认100毫秒
     */
    private long taskRpcRetryDelay = 100;

    /**
     * 运行主机ID
     */
    private String hostId = ManagementFactory.getRuntimeMXBean().getName();

    /**
     * 任务服务器
     */
    private String taskCenterHost = "127.0.0.1";

    /**
     * Redis配置
     */
    private RedisProperties redis = new RedisProperties();

    /**
     * Rabbit MQ配置
     */
    private RabbitProperties rabbitmq = new RabbitProperties();

    public static class RedisProperties extends org.springframework.boot.autoconfigure.data.redis.RedisProperties {

    }

    public static class RabbitProperties extends org.springframework.boot.autoconfigure.amqp.RabbitProperties {

    }

    public boolean isEnableTaskRegistry() {
        return enableTaskRegistry;
    }

    public void setEnableTaskRegistry(boolean enableTaskRegistry) {
        this.enableTaskRegistry = enableTaskRegistry;
    }

    /**
	 * @return the privacyMode
	 */
	public boolean isPrivacyMode() {
		return privacyMode;
	}

	/**
	 * @param privacyMode the privacyMode to set
	 */
	public void setPrivacyMode(boolean privacyMode) {
		this.privacyMode = privacyMode;
	}

	public int getTaskRpcMinThreadNum() {
		return taskRpcMinThreadNum;
	}

	public void setTaskRpcMinThreadNum(int taskRpcMinThreadNum) {
		this.taskRpcMinThreadNum = taskRpcMinThreadNum;
	}

	public int getTaskRpcMaxThreadNum() {
		return taskRpcMaxThreadNum;
	}

	public void setTaskRpcMaxThreadNum(int taskRpcMaxThreadNum) {
		this.taskRpcMaxThreadNum = taskRpcMaxThreadNum;
	}

	/**
     * @return the project
     */
    public String getProject() {
        return project;
    }

    /**
     * @param project the project to set
     */
    public void setProject(String project) {
        this.project = project;
    }

    /**
     * @return the hostId
     */
    public String getHostId() {
        return hostId;
    }

    /**
     * @param hostId the hostId to set
     */
    public void setHostId(String hostId) {
        this.hostId = hostId;
    }

    /**
	 * @return the cronerThreadNum
	 */
	public int getCronerThreadNum() {
		return cronerThreadNum;
	}

	/**
	 * @param cronerThreadNum the cronerThreadNum to set
	 */
	public void setCronerThreadNum(int cronerThreadNum) {
		this.cronerThreadNum = cronerThreadNum;
	}

	/**
     * @return the taskCenterHost
     */
    public String getTaskCenterHost() {
        return taskCenterHost;
    }

    /**
     * @param taskCenterHost the taskCenterHost to set
     */
    public void setTaskCenterHost(String taskCenterHost) {
        this.taskCenterHost = taskCenterHost;
    }

    public RedisProperties getRedis() {
        return redis;
    }

    public void setRedis(RedisProperties redis) {
        this.redis = redis;
    }

    public RabbitProperties getRabbitmq() {
        return rabbitmq;
    }

    public void setRabbitmq(RabbitProperties rabbitmq) {
        this.rabbitmq = rabbitmq;
    }

    public long getTaskQueueRetryDelay() {
        return taskQueueRetryDelay;
    }

    public void setTaskQueueRetryDelay(long taskQueueRetryDelay) {
        this.taskQueueRetryDelay = taskQueueRetryDelay;
    }

    public long getTaskRpcRetryDelay() {
        return taskRpcRetryDelay;
    }

    public void setTaskRpcRetryDelay(long taskRpcRetryDelay) {
        this.taskRpcRetryDelay = taskRpcRetryDelay;
    }
}


Question: package uw.task.container;
import java.util.ArrayList;
import java.util.Date;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import uw.task.TaskData;
import uw.task.TaskFactory;
import uw.task.TaskListenerManager;
import uw.task.TaskRunner;
import uw.task.api.TaskAPI;
import uw.task.conf.TaskMetaInfoManager;
import uw.task.conf.TaskProperties;
import uw.task.entity.TaskRunnerConfig;
import uw.task.entity.TaskRunnerLog;
import uw.task.exception.TaskDataException;
import uw.task.exception.TaskPartnerException;
import uw.task.listener.RunnerTaskListener;
import uw.task.util.GlobalRateLimiter;
import uw.task.util.LocalRateLimiter;
import uw.task.util.MiscUtils;




/**
 * 在此处接受MQ信息，并进行处理。
 *
 * @author axeon
 */
public class TaskRunnerContainer {

    private static final Logger log = LoggerFactory.getLogger(TaskRunnerContainer.class);

    /**
     * TaskFactory
     */
    private TaskFactory taskFactory;

    /**
     * 服务端任务API
     */
    private TaskAPI taskAPI;

    /**
     * 全局流量限制服务
     */
    private GlobalRateLimiter globalRateLimiter;

    /**
     * 本地流量限制服务
     */
Answer:     private LocalRateLimiter localRateLimiter;