xxl-job客户端如何接入spring boot,按xxl-job官方给出来的demo,需要以下几个过程
1、======================================================================
### xxl-job admin address list, such as "http://address" or "http://address01,http://address02"
xxl.job.admin.addresses=http://127.0.0.1:8080/xxl-job-admin,http://192.168.1.168:1888/xxl-job-admin
### xxl-job executor address
xxl.job.executor.appname=app-job-executor
xxl.job.executor.ip=
xxl.job.executor.port=9998
### xxl-job, access token
xxl.job.accessToken=
### xxl-job log path
xxl.job.executor.logpath=D:/xxl-job
### xxl-job log retention days
xxl.job.executor.logretentiondays=-1
2、=========================================================================
@Configuration
@ComponentScan(basePackages = "com.xxl.job.executor.service.jobhandler")
3、=========================================================================
@Bean(initMethod = "start", destroyMethod = "destroy")
public XxlJobSpringExecutor xxlJobExecutor() {
logger.info(">>>>>>>>>>> xxl-job config init.");
XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();
xxlJobSpringExecutor.setAdminAddresses(adminAddresses);
xxlJobSpringExecutor.setAppName(appName);
xxlJobSpringExecutor.setIp(ip);
xxlJobSpringExecutor.setPort(port);
xxlJobSpringExecutor.setAccessToken(accessToken);
xxlJobSpringExecutor.setLogPath(logPath);
xxlJobSpringExecutor.setLogRetentionDays(logRetentionDays);
return xxlJobSpringExecutor;
}
ok,那我们分析一下主要的init流程与接收调度中心调度请求的流程
1、首先定位到XxlJobSpringExecutor的initMethod,start()
@Override
public void start() throws Exception {
//初始化jobHandler
initJobHandlerRepository(applicationContext);
// refresh GlueFactory
GlueFactory.refreshInstance(1);
// super start
super.start();
}
private void initJobHandlerRepository(ApplicationContext applicationContext){
if (applicationContext == null) {
return;
}
// 从spring中拿到JobHandler注解的bean map
Map serviceBeanMap = applicationContext.getBeansWithAnnotation(JobHandler.class);
if (serviceBeanMap!=null && serviceBeanMap.size()>0) {
for (Object serviceBean : serviceBeanMap.values()) {
//判断是否IJobHandler
if (serviceBean instanceof IJobHandler){
String name = serviceBean.getClass().getAnnotation(JobHandler.class).value();
IJobHandler handler = (IJobHandler) serviceBean;
if (loadJobHandler(name) != null) {
throw new RuntimeException("xxl-job jobhandler naming conflicts.");
}
//拿到JobHandler注解的名字,以及IJobHandler放入jobHandlerRepository中
registJobHandler(name, handler);
}
}
}
}
// ---------------------- job handler repository ----------------------
private static ConcurrentHashMap jobHandlerRepository = new ConcurrentHashMap();
public static IJobHandler registJobHandler(String name, IJobHandler jobHandler){
logger.info(">>>>>>>>>>> xxl-job register jobhandler success, name:{}, jobHandler:{}", name, jobHandler);
return jobHandlerRepository.put(name, jobHandler);
}
2、调用父类XxlJobExecutor的start()方法,首先我们看initAdminBizList();
private static List adminBizList;
//拿到我们刚才设置的adminAddresses列表(xxl.job.admin.addresses)
private void initAdminBizList(String adminAddresses, String accessToken) throws Exception {
if (adminAddresses!=null && adminAddresses.trim().length()>0) {
for (String address: adminAddresses.trim().split(",")) {
if (address!=null && address.trim().length()>0) {
//addressUrl地址:http://127.0.0.1:8080/xxl-job-admin/api
String addressUrl = address.concat(AdminBiz.MAPPING);
//通过XxlRpcReferenceBean#getObject()设置动态代理,主要用来请求和处理rpc信息,这里使用的是JETTY,JettyServer和JettyClient去处理,还支持mima,netty等的扩展
AdminBiz adminBiz = (AdminBiz) new XxlRpcReferenceBean(NetEnum.JETTY, Serializer.SerializeEnum.HESSIAN.getSerializer(), CallType.SYNC,
AdminBiz.class, null, 10000, addressUrl, accessToken, null).getObject();
if (adminBizList == null) {
adminBizList = new ArrayList();
}
//放入adminBizList中
adminBizList.add(adminBiz);
}
}
}
}
//XxlRpcReferenceBean#getObject()
public Object getObject() {
return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[]{this.iface}, new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//....代码太多,略过
}
}
});
}
3、启动日志清理守护线程
//感兴趣可以自己看
JobLogFileCleanThread.getInstance().start(logRetentionDays);
4、启动触发器回调守护线程
TriggerCallbackThread.getInstance().start();
/******************************************************************/
//判断我们在步骤2中获取到的adminBizList是否有值
if (XxlJobExecutor.getAdminBizList() == null) {
return;
}
//启动任务执行完成的回调线程
triggerCallbackThread = new Thread(new Runnable() {
@Override
public void run() {
// normal callback
while(!toStop){
try {
//使用一个无界队列(LinkedBlockingQueue)保存执行结果,并take()得到就执行回调
HandleCallbackParam callback = getInstance().callBackQueue.take();
if (callback != null) {
// callback list param
List callbackParamList = new ArrayList();
//移除队列中可用的元素,加入到callBackParamList中
int drainToNum = getInstance().callBackQueue.drainTo(callbackParamList);
callbackParamList.add(callback);
// callback, will retry if error
if (callbackParamList!=null && callbackParamList.size()>0) {
//执行doCallBack方法,看下方
doCallback(callbackParamList);
}
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
}
// last callback
try {
List callbackParamList = new ArrayList();
int drainToNum = getInstance().callBackQueue.drainTo(callbackParamList);
if (callbackParamList!=null && callbackParamList.size()>0) {
doCallback(callbackParamList);
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
logger.info(">>>>>>>>>>> xxl-job, executor callback thread destory.");
}
});
triggerCallbackThread.setDaemon(true);
triggerCallbackThread.start();
private void doCallback(List callbackParamList){
boolean callbackRet = false;
// callback, will retry if error
for (AdminBiz adminBiz: XxlJobExecutor.getAdminBizList()) {
try {
//AdminBiz->刚刚用XxlRpcReferenceBean设置动态代理的对象
//实际上会通过XxlRpcRequest调用xxl-job-admin /api接口
//并通过XxlRpcProviderFactory,使用反射,调用adminBiz的实现类的callBack方法
ReturnT callbackResult = adminBiz.callback(callbackParamList);
if (callbackResult!=null && ReturnT.SUCCESS_CODE == callbackResult.getCode()) {
callbackLog(callbackParamList, "
----------- xxl-job job callback finish.");
callbackRet = true;
break;
} else {
callbackLog(callbackParamList, "
----------- xxl-job job callback fail, callbackResult:" + callbackResult);
}
} catch (Exception e) {
callbackLog(callbackParamList, "
----------- xxl-job job callback error, errorMsg:" + e.getMessage());
}
}
if (!callbackRet) {
appendFailCallbackFile(callbackParamList);
}
}
5、执行initRpcProvider(),默认jetty启动端口是9999,并开启
private void initRpcProvider(String ip, int port, String appName, String accessToken) throws Exception {
// init invoker factory
xxlRpcInvokerFactory = new XxlRpcInvokerFactory();
// init, provider factory
//执行器执行地址
String address = IpUtil.getIpPort(ip, port);
Map serviceRegistryParam = new HashMap();
serviceRegistryParam.put("appName", appName);
serviceRegistryParam.put("address", address);
xxlRpcProviderFactory = new XxlRpcProviderFactory();
//初始化xxlRpcProvinderFactory
xxlRpcProviderFactory.initConfig(NetEnum.JETTY, Serializer.SerializeEnum.HESSIAN.getSerializer(), ip, port, accessToken, ExecutorServiceRegistry.class, serviceRegistryParam);
// add services
xxlRpcProviderFactory.addService(ExecutorBiz.class.getName(), null, new ExecutorBizImpl());
// start
xxlRpcProviderFactory.start();
}
6、(代码较多)启动刚才在步骤2中设置的NetEnum的JettyServer,并设置开启后的回调方法和关闭回调方法
public void start() throws Exception {
//1、指定server为JettyServer
this.server = (Server)this.netType.serverClass.newInstance();
//2、设置启动后的回调
this.server.setStartedCallback(new BaseCallback() {
public void run() throws Exception {
if (XxlRpcProviderFactory.this.serviceRegistryClass != null) {
//实例化XxlRpcProviderFactory
XxlRpcProviderFactory.this.serviceRegistry = (ServiceRegistry)XxlRpcProviderFactory.this.serviceRegistryClass.newInstance();
//调用ExecutorServiceRegistry的start方法,启动一个ExecutorRegistryThread守护线程,每30秒去注册一次 XxlRpcProviderFactory.this.serviceRegistry.start(XxlRpcProviderFactory.this.serviceRegistryParam);
if (XxlRpcProviderFactory.this.serviceData.size() > 0) {
String ipPort = IpUtil.getIpPort(XxlRpcProviderFactory.this.ip, XxlRpcProviderFactory.this.port);
Iterator i$ = XxlRpcProviderFactory.this.serviceData.keySet().iterator();
while(i$.hasNext()) {
String serviceKey = (String)i$.next();
XxlRpcProviderFactory.this.serviceRegistry.registry(serviceKey, ipPort);
}
}
}
}
});
//3、设置关闭后的回调
this.server.setStopedCallback(new BaseCallback() {
public void run() {
if (XxlRpcProviderFactory.this.serviceRegistry != null) {
if (XxlRpcProviderFactory.this.serviceData.size() > 0) {
String ipPort = IpUtil.getIpPort(XxlRpcProviderFactory.this.ip, XxlRpcProviderFactory.this.port);
Iterator i$ = XxlRpcProviderFactory.this.serviceData.keySet().iterator();
while(i$.hasNext()) {
String serviceKey = (String)i$.next();
XxlRpcProviderFactory.this.serviceRegistry.remove(serviceKey, ipPort);
}
}
XxlRpcProviderFactory.this.serviceRegistry.stop();
XxlRpcProviderFactory.this.serviceRegistry = null;
}
}
});
//4、开启jetty服务
this.server.start(this);
}
//4、JettyServer#start()
public void start(final XxlRpcProviderFactory xxlRpcProviderFactory) throws Exception {
this.thread = new Thread(new Runnable() {
public void run() {
JettyServer.this.server = new org.eclipse.jetty.server.Server(new QueuedThreadPool());
ServerConnector connector = new ServerConnector(JettyServer.this.server);
connector.setPort(xxlRpcProviderFactory.getPort());
JettyServer.this.server.setConnectors(new Connector[]{connector});
HandlerCollection handlerc = new HandlerCollection();
//****设置接收xxl-job-admin rpc请求处理
handlerc.setHandlers(new Handler[]{new JettyServerHandler(xxlRpcProviderFactory)});
JettyServer.this.server.setHandler(handlerc);
try {
//开启jetty
JettyServer.this.server.start();
JettyServer.logger.info(">>>>>>>>>>> xxl-rpc remoting server start success, nettype = {}, port = {}", JettyServer.class.getName(), xxlRpcProviderFactory.getPort());
//回调步骤2
JettyServer.this.onStarted();
//让出时间片
JettyServer.this.server.join();
} catch (Exception var12) {
JettyServer.logger.error(">>>>>>>>>>> xxl-rpc remoting server start error.", var12);
} finally {
try {
JettyServer.this.stop();
} catch (Exception var11) {
JettyServer.logger.error(var11.getMessage(), var11);
}
}
}
});
this.thread.setDaemon(true);
this.thread.start();
}
//5、执行开启后的回调(步骤2),执行注册
public void onStarted() {
if (this.startedCallback != null) {
try {
this.startedCallback.run();
} catch (Exception var2) {
logger.error(">>>>>>>>>>> xxl-rpc, server startedCallback error.", var2);
}
}
}
7、延续一下6的注册过程,通过rpc每30秒注册到xxl-job-admin一次
//ExecutorRegistryThread#start()
public void start(final String appName, final String address){
// valid
if (appName==null || appName.trim().length()==0) {
logger.warn(">>>>>>>>>>> xxl-job, executor registry config fail, appName is null.");
return;
}
if (XxlJobExecutor.getAdminBizList() == null) {
logger.warn(">>>>>>>>>>> xxl-job, executor registry config fail, adminAddresses is null.");
return;
}
registryThread = new Thread(new Runnable() {
@Override
public void run() {
// registry
while (!toStop) {
try {
//构建注册请求参数
RegistryParam registryParam = new RegistryParam(RegistryConfig.RegistType.EXECUTOR.name(), appName, address);
for (AdminBiz adminBiz: XxlJobExecutor.getAdminBizList()) {
try {
//调用XxlRpcReferenceBean动态代理方法getObject(),执行xxl-job-admin的api接口,执行AdminBiz子类的registry方法
ReturnT registryResult = adminBiz.registry(registryParam);
if (registryResult!=null && ReturnT.SUCCESS_CODE == registryResult.getCode()) {
registryResult = ReturnT.SUCCESS;
logger.info(">>>>>>>>>>> xxl-job registry success, registryParam:{}, registryResult:{}", new Object[]{registryParam, registryResult});
break;
} else {
logger.info(">>>>>>>>>>> xxl-job registry fail, registryParam:{}, registryResult:{}", new Object[]{registryParam, registryResult});
}
} catch (Exception e) {
logger.info(">>>>>>>>>>> xxl-job registry error, registryParam:{}", registryParam, e);
}
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
try {
//每30秒执行一次
TimeUnit.SECONDS.sleep(RegistryConfig.BEAT_TIMEOUT);
} catch (InterruptedException e) {
logger.warn(">>>>>>>>>>> xxl-job, executor registry thread interrupted, error msg:{}", e.getMessage());
}
}
// registry remove
//触发toStop之后,会停止注册,并一样通过rpc调用registryRemove()方法
try {
RegistryParam registryParam = new RegistryParam(RegistryConfig.RegistType.EXECUTOR.name(), appName, address);
for (AdminBiz adminBiz: XxlJobExecutor.getAdminBizList()) {
try {
ReturnT registryResult = adminBiz.registryRemove(registryParam);
if (registryResult!=null && ReturnT.SUCCESS_CODE == registryResult.getCode()) {
registryResult = ReturnT.SUCCESS;
logger.info(">>>>>>>>>>> xxl-job registry-remove success, registryParam:{}, registryResult:{}", new Object[]{registryParam, registryResult});
break;
} else {
logger.info(">>>>>>>>>>> xxl-job registry-remove fail, registryParam:{}, registryResult:{}", new Object[]{registryParam, registryResult});
}
} catch (Exception e) {
logger.info(">>>>>>>>>>> xxl-job registry-remove error, registryParam:{}", registryParam, e);
}
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
logger.info(">>>>>>>>>>> xxl-job, executor registry thread destory.");
}
});
registryThread.setDaemon(true);
registryThread.start();
}
8、处理rpc请求,刚才在启动jetty的时候设置了HandlerConnection为JettyServerHandler
public class JettyServerHandler extends AbstractHandler {
//处理rpc请求
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
StringBuffer stringBuffer;
if (!"/services".equals(target)) {
stringBuffer = null;
XxlRpcRequest xxlRpcRequest;
try {
//读取流并反序列化
xxlRpcRequest = this.parseRequest(request);
} catch (Exception var8) {
//反序列化失败就返回异常
this.writeResponse(baseRequest, response, ThrowableUtil.toString(var8).getBytes());
return;
}
//构建返回结果
XxlRpcResponse xxlRpcResponse = this.xxlRpcProviderFactory.invokeService(xxlRpcRequest);
byte[] responseBytes = this.xxlRpcProviderFactory.getSerializer().serialize(xxlRpcResponse);
//序列化后返回给xxl-job-admin
this.writeResponse(baseRequest, response, responseBytes);
} else {
stringBuffer = new StringBuffer("");
Iterator i$ = this.xxlRpcProviderFactory.getServiceData().keySet().iterator();
while(i$.hasNext()) {
String serviceKey = (String)i$.next();
stringBuffer.append("").append(serviceKey).append(": ").append(this.xxlRpcProviderFactory.getServiceData().get(serviceKey)).append(" ");
}
stringBuffer.append(" ");
this.writeResponse(baseRequest, response, stringBuffer.toString().getBytes());
}
}
}
//XxlRpcProviderFactory#invokeService
public XxlRpcResponse invokeService(XxlRpcRequest xxlRpcRequest) {
//构建返回结果response
XxlRpcResponse xxlRpcResponse = new XxlRpcResponse();
xxlRpcResponse.setRequestId(xxlRpcRequest.getRequestId());
String serviceKey = makeServiceKey(xxlRpcRequest.getClassName(), xxlRpcRequest.getVersion());
//获取执行的服务,步骤5设置
Object serviceBean = this.serviceData.get(serviceKey);
if (serviceBean == null) {
xxlRpcResponse.setErrorMsg("The serviceKey[" + serviceKey + "] not found.");
return xxlRpcResponse;
} else if (System.currentTimeMillis() - xxlRpcRequest.getCreateMillisTime() > 180000L) {
xxlRpcResponse.setErrorMsg("The timestamp difference between admin and executor exceeds the limit.");
return xxlRpcResponse;
} else if (this.accessToken != null && this.accessToken.trim().length() > 0 && !this.accessToken.trim().equals(xxlRpcRequest.getAccessToken())) {
xxlRpcResponse.setErrorMsg("The access token[" + xxlRpcRequest.getAccessToken() + "] is wrong.");
return xxlRpcResponse;
} else {
try {
Class> serviceClass = serviceBean.getClass();
//run
String methodName = xxlRpcRequest.getMethodName();
Class>[] parameterTypes = xxlRpcRequest.getParameterTypes();
Object[] parameters = xxlRpcRequest.getParameters();
Method method = serviceClass.getMethod(methodName, parameterTypes);
method.setAccessible(true);
//通过反射执行对应的方法,这里调用的是ExecutorBizImpl#run()
Object result = method.invoke(serviceBean, parameters);
xxlRpcResponse.setResult(result);
} catch (Throwable var11) {
logger.error("xxl-rpc provider invokeService error.", var11);
xxlRpcResponse.setErrorMsg(ThrowableUtil.toString(var11));
}
return xxlRpcResponse;
}
}
9、执行ExecutorBizImpl#run方法,从而执行最终的IJobHandler#executor方法
public ReturnT run(TriggerParam triggerParam) {
//先判断是否存在处理jobId的jobThread,不存在就注册一个
JobThread jobThread = XxlJobExecutor.loadJobThread(triggerParam.getJobId());
//获取IJobHandler
IJobHandler jobHandler = jobThread!=null?jobThread.getHandler():null;
String removeOldReason = null;
// valid:jobHandler + jobThread
GlueTypeEnum glueTypeEnum = GlueTypeEnum.match(triggerParam.getGlueType());
if (GlueTypeEnum.BEAN == glueTypeEnum) {
// 根据jobHandler的名称,获取我们一开始就存入jobHandlerResp中的IJobHandler
IJobHandler newJobHandler = XxlJobExecutor.loadJobHandler(triggerParam.getExecutorHandler());
// valid old jobThread
if (jobThread!=null && jobHandler != newJobHandler) {
// change handler, need kill old thread
removeOldReason = "change jobhandler or glue type, and terminate the old job thread.";
jobThread = null;
jobHandler = null;
}
// valid handler
//如果是第一次触发,jobHandler为空,那么就设置对应的jobHandler
if (jobHandler == null) {
jobHandler = newJobHandler;
if (jobHandler == null) {
return new ReturnT(ReturnT.FAIL_CODE, "job handler [" + triggerParam.getExecutorHandler() + "] not found.");
}
}
}
//.....这里去掉了 我们没分析的glue模式
// executor block strategy
//jobThread不为空,说明任务执行中,这个时候可以通过阻塞策略做对应的动作
//比如说丢弃、覆盖等,具体可以看xxl-job-admin任务的阻塞策略
if (jobThread != null) {
ExecutorBlockStrategyEnum blockStrategy = ExecutorBlockStrategyEnum.match(triggerParam.getExecutorBlockStrategy(), null);
//执行丢弃后续调度逻辑
if (ExecutorBlockStrategyEnum.DISCARD_LATER == blockStrategy) {
// discard when running
if (jobThread.isRunningOrHasQueue()) {
return new ReturnT(ReturnT.FAIL_CODE, "block strategy effect:"+ExecutorBlockStrategyEnum.DISCARD_LATER.getTitle());
}
//覆盖之前调度逻辑
} else if (ExecutorBlockStrategyEnum.COVER_EARLY == blockStrategy) {
// kill running jobThread
if (jobThread.isRunningOrHasQueue()) {
removeOldReason = "block strategy effect:" + ExecutorBlockStrategyEnum.COVER_EARLY.getTitle();
jobThread = null;
}
} else {
// just queue trigger
}
}
//如果是第一次执行,那么就新建一个jobThread,并start(),并放入XxlJobExecutor.jobThreadRepository中
// replace thread (new or exists invalid)
if (jobThread == null) {
jobThread = XxlJobExecutor.registJobThread(triggerParam.getJobId(), jobHandler, removeOldReason);
}
// push data to queue
//放入执行队列,实现快速的吞吐
ReturnT pushResult = jobThread.pushTriggerQueue(triggerParam);
return pushResult;
}
10、由于开启了JobThread,所以最后处理逻辑就来到了JobThread的run()中,会一直检查一次队列中是否有待执行任务
public void run() {
// init
try {
//IJobHandler#init()方法,这里我们没用到
handler.init();
} catch (Throwable e) {
logger.error(e.getMessage(), e);
}
// execute
while(!toStop){
running = false;
//等待时间
idleTimes++;
TriggerParam triggerParam = null;
ReturnT executeResult = null;
try {
// to check toStop signal, we need cycle, so wo cannot use queue.take(), instand of poll(timeout)
//从触发队列中获取待触发任务,3秒超时
triggerParam = triggerQueue.poll(3L, TimeUnit.SECONDS);
if (triggerParam!=null) {
running = true;
idleTimes = 0;
triggerLogIdSet.remove(triggerParam.getLogId());
// log filename, like "logPath/yyyy-MM-dd/9999.log"
String logFileName = XxlJobFileAppender.makeLogFileName(new Date(triggerParam.getLogDateTim()), triggerParam.getLogId());
XxlJobFileAppender.contextHolder.set(logFileName);
//设置分片信息
ShardingUtil.setShardingVo(new ShardingUtil.ShardingVO(triggerParam.getBroadcastIndex(), triggerParam.getBroadcastTotal()));
// execute
XxlJobLogger.log("
----------- xxl-job job execute start -----------
----------- Param:" + triggerParam.getExecutorParams());
//判断是否有执行超时的设置
if (triggerParam.getExecutorTimeout() > 0) {
// limit timeout
Thread futureThread = null;
try {
final TriggerParam triggerParamTmp = triggerParam;
//有的话则通过futurnTask去做,jdk8做有类似做法的还有CompletableFuture.supplyAsync(()->{ }).get()
FutureTask> futureTask = new FutureTask>(new Callable>() {
@Override
public ReturnT call() throws Exception {
//执行IJobHandler#execute
return handler.execute(triggerParamTmp.getExecutorParams());
}
});
futureThread = new Thread(futureTask);
futureThread.start();
//异步执行,设置超时
executeResult = futureTask.get(triggerParam.getExecutorTimeout(), TimeUnit.SECONDS);
} catch (TimeoutException e) {
XxlJobLogger.log("
----------- xxl-job job execute timeout");
XxlJobLogger.log(e);
executeResult = new ReturnT(IJobHandler.FAIL_TIMEOUT.getCode(), "job execute timeout ");
} finally {
//中断future线程
futureThread.interrupt();
}
} else {
// just execute
//没设置超时,直接执行IJobHandler#execute
executeResult = handler.execute(triggerParam.getExecutorParams());
}
if (executeResult == null) {
executeResult = IJobHandler.FAIL;
}
XxlJobLogger.log("
----------- xxl-job job execute end(finish) -----------
----------- ReturnT:" + executeResult);
} else {
//等待时间不能超过30秒
if (idleTimes > 30) {
XxlJobExecutor.removeJobThread(jobId, "excutor idel times over limit.");
}
}
} catch (Throwable e) {
if (toStop) {
XxlJobLogger.log("
----------- JobThread toStop, stopReason:" + stopReason);
}
StringWriter stringWriter = new StringWriter();
e.printStackTrace(new PrintWriter(stringWriter));
String errorMsg = stringWriter.toString();
executeResult = new ReturnT(ReturnT.FAIL_CODE, errorMsg);
XxlJobLogger.log("
----------- JobThread Exception:" + errorMsg + "
----------- xxl-job job execute end(error) -----------");
} finally {
if(triggerParam != null) {
// callback handler info
if (!toStop) {
// 把执行结果放入TriggerCallbackThread中的callBack队列,进行结果回调
TriggerCallbackThread.pushCallBack(new HandleCallbackParam(triggerParam.getLogId(), triggerParam.getLogDateTim(), executeResult));
} else {
// is killed
ReturnT stopResult = new ReturnT(ReturnT.FAIL_CODE, stopReason + " [job running,killed]");
TriggerCallbackThread.pushCallBack(new HandleCallbackParam(triggerParam.getLogId(), triggerParam.getLogDateTim(), stopResult));
}
}
}
}
// callback trigger request in queue
while(triggerQueue !=null && triggerQueue.size()>0){
TriggerParam triggerParam = triggerQueue.poll();
if (triggerParam!=null) {
// is killed
ReturnT stopResult = new ReturnT(ReturnT.FAIL_CODE, stopReason + " [job not executed, in the job queue, killed.]");
TriggerCallbackThread.pushCallBack(new HandleCallbackParam(triggerParam.getLogId(), triggerParam.getLogDateTim(), stopResult));
}
}
// destroy
try {
handler.destroy();
} catch (Throwable e) {
logger.error(e.getMessage(), e);
}
logger.info(">>>>>>>>>>> xxl-job JobThread stoped, hashCode:{}", Thread.currentThread());
}
至此、客户端执行器初始化bean与接收rpc请求处理流程简单分析解析