xxl-job原理-- 执行器注册

  1. 执行器注册

需要有一个调度中心,其他注册器将自己注册到调度中心,然后就可以接任务了。
缺点, 调度中心不能自我注册
2. 注册方式

自动注册
手动录入

主动注册中就是在配置中心,设置配置信息 xxl.job.admin.address=, xxl.job.executor.appName=, 注意appName不可以重复
手动录入,其中的Appname是不能重复的
自动注册流程

在执行器启动时会读取配置,当存在任务调度中心地址会依次向任务调度中心注册其地址.

填写配置信息

xxl-job admin address list, such as "http://address" or "http://address01,http://address02"

任务调度中心地址, 多个地址有逗号隔开

xxl.job.admin.addresses=http://127.0.0.1:7995/xxl-job-admin/

xxl-job executor address

任务调度器名称和机器信息

xxl.job.executor.appname=xxl-job-executor-sample
xxl.job.executor.ip=127.0.0.1
xxl.job.executor.port=9999

查找流程

xxl-job-executor-service

@Configuration 注解的XxlJobConfig ----> @Bean 修饰的xxlJobExecutor方法

@Bean(initMethod = "start", destroyMethod = "destroy")
public XxlJobSpringExecutor xxlJobExecutor() {
// xxl-job 配置信息初始化, 初始化 执行器的基本信息, appname, ip, port, accessToken, logpath, logretentionDays
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;
}

注意@Bean的 initMethod 与 destroyMethod
xxl-job-core:2.0.2

public class XxlJobSpringExecutor extends XxlJobExecutor implements ApplicationContextAware {
@Override
public void start() throws Exception {
// init JobHandler Repository
initJobHandlerRepository(applicationContext);
// refresh GlueFactory
GlueFactory.refreshInstance(1);
// super start
super.start();
}
private void initJobHandlerRepository(ApplicationContext applicationContext){
...
// init job handler action, 根据应用上下文获取ServiceBeanMap,
// ServiceBeanMap的value包含IJobHandler的子类
// class DemoJobHandler extends IJobHandler , 该DemoJobHandler 就是
Map<String, Object> serviceBeanMap = applicationContext.getBeansWithAnnotation(JobHandler.class);
if (serviceBeanMap!=null && serviceBeanMap.size()>0) {
for (Object serviceBean : serviceBeanMap.values()) {
if (serviceBean instanceof IJobHandler){
// 获取@JobHandler(value="demoJobHandler") 定义的value值
String name = serviceBean.getClass().getAnnotation(JobHandler.class).value();
IJobHandler handler = (IJobHandler) serviceBean;
// 从jobHandlerRepository中查找demoJobHandler值, 如果有,抛出异常
if (loadJobHandler(name) != null) {
throw new RuntimeException("xxl-job jobhandler naming conflicts.");
}
// 没有就将该demoJobHandler 注册到 jobHandlerRepository中, xxl-job register jobhandler success
// jobHandlerRepository 是有ConcurrentHashMap 类, key: String, value : IJobHandler以及子类
registJobHandler(name, handler);
}
}
}
}
......

}

XxlJobExecutor
public static IJobHandler loadJobHandler(String name){
return jobHandlerRepository.get(name);
}

GlueFactory
// 创建glueFactory实例, 用于根据name生成实例
public static void refreshInstance(int type){
if (type == 0) {
glueFactory = new GlueFactory();
} else if (type == 1) {
// 主要使用SpringGlueFactory
glueFactory = new SpringGlueFactory();
}
}

XxlJobExecutor.start()
// ---------------------- start + stop ----------------------
public void start() throws Exception {

    // init logpath  

// 初始化log日志文件,
// 默认的日志路径为/data/applogs/xxl-job/jobhandler
// 如果日志不存在就设置为/data/applogs/xxl-job/jobhandler, 创建响应的目录,
// 如果/data/applogs/xxl-job/jobhandler/gluesource不存在,就创建
XxlJobFileAppender.initLogPath(logPath);

    // init invoker, admin-client
    initAdminBizList(adminAddresses, accessToken);


    // init JobLogFileCleanThread
    JobLogFileCleanThread.getInstance().start(logRetentionDays);

    // init TriggerCallbackThread
    TriggerCallbackThread.getInstance().start();

    // init executor-server
    port = port>0?port: NetUtil.findAvailablePort(9999);
    ip = (ip!=null&&ip.trim().length()>0)?ip: IpUtil.getIp();
    initRpcProvider(ip, port, appName, accessToken);
}

XxlJobExecutor.initAdminBizList
// ---------------------- admin-client (rpc invoker) ----------------------
private static List adminBizList;
private static Serializer serializer;
//当存在多个任务调度中心时,创建代理类并注册,在NetComClientProxy
private void initAdminBizList(String adminAddresses, String accessToken) throws Exception {
// 获取Serializer(抽象类) 子类实例
serializer = Serializer.SerializeEnum.HESSIAN.getSerializer();
// 当存在多个任务调度中心
if (adminAddresses!=null && adminAddresses.trim().length()>0) {
for (String address: adminAddresses.trim().split(",")) {
if (address!=null && address.trim().length()>0) {
// address 连接上/api
String addressUrl = address.concat(AdminBiz.MAPPING);
// 构建 xxlRpcRefrenceBean 实例 , 注意这些属性信息
AdminBiz adminBiz = (AdminBiz) new XxlRpcReferenceBean(
// 使用 netty_http 实现RPC, 在v2.0.1 使用的是 Jetty_http , v2.0.2 使用的是Netty_http
NetEnum.NETTY_HTTP,
// Serializer 实例
serializer,
// CallType 调用方式, SYNC 同步
CallType.SYNC,
// LoadBalance 方式, 路由策略为 轮询
LoadBalance.ROUND,
// AdminBiz 类
AdminBiz.class,
// version 版本
null,
// timeout 超时时间
10000,
// 注册中心地址
addressUrl,
// 权限控制
accessToken,
// invokeCallback 回调
null,
// invokerFactory 调用工厂
null
).getObject(); // 使用动态代理生成AdminBiz 实现类
// 存储 adminBiz实例
if (adminBizList == null) {
adminBizList = new ArrayList();
}
adminBizList.add(adminBiz);
}
}
}
}

getObject
XxlRpcReferenceBean
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 {
String className = method.getDeclaringClass().getName();
String varsion_ = XxlRpcReferenceBean.this.version;
String methodName = method.getName();
Class[] parameterTypes = method.getParameterTypes(); Object[] parameters = args; if (className.equals(XxlRpcGenericService.class.getName()) && methodName.equals("invoke")) { Class[] paramTypes = null;
if (args[3] != null) {
String[] paramTypes_str = (String[])((String[])args[3]);
if (paramTypes_str.length > 0) {
paramTypes = new Class[paramTypes_str.length];

                        for(int i = 0; i < paramTypes_str.length; ++i) {
                            paramTypes[i] = ClassUtil.resolveClass(paramTypes_str[i]);
                        }
                    }
                }

                className = (String)args[0];
                varsion_ = (String)args[1];
                methodName = (String)args[2];
                parameterTypes = paramTypes;
                parameters = (Object[])((Object[])args[4]);
            }

            if (className.equals(Object.class.getName())) {
                XxlRpcReferenceBean.logger.info(">>>>>>>>>>> xxl-rpc proxy class-method not support [{}#{}]", className, methodName);
                throw new XxlRpcException("xxl-rpc proxy class-method not support");
            } else {
                String finalAddress = XxlRpcReferenceBean.this.address;
                if ((finalAddress == null || finalAddress.trim().length() == 0) && XxlRpcReferenceBean.this.invokerFactory != null && XxlRpcReferenceBean.this.invokerFactory.getServiceRegistry() != null) {
                    String serviceKey = XxlRpcProviderFactory.makeServiceKey(className, varsion_);
                    TreeSet<String> addressSet = XxlRpcReferenceBean.this.invokerFactory.getServiceRegistry().discovery(serviceKey);
                    if (addressSet != null && addressSet.size() != 0) {
                        if (addressSet.size() == 1) {
                            finalAddress = (String)addressSet.first();
                        } else {
                            finalAddress = XxlRpcReferenceBean.this.loadBalance.xxlRpcInvokerRouter.route(serviceKey, addressSet);
                        }
                    }
                }

                if (finalAddress != null && finalAddress.trim().length() != 0) {
                    XxlRpcRequest xxlRpcRequest = new XxlRpcRequest();
                    xxlRpcRequest.setRequestId(UUID.randomUUID().toString());
                    xxlRpcRequest.setCreateMillisTime(System.currentTimeMillis());
                    xxlRpcRequest.setAccessToken(XxlRpcReferenceBean.this.accessToken);
                    xxlRpcRequest.setClassName(className);
                    xxlRpcRequest.setMethodName(methodName);
                    xxlRpcRequest.setParameterTypes(parameterTypes);
                    xxlRpcRequest.setParameters(parameters);
                    XxlRpcFutureResponse futureResponse;

// 使用同步调用方式,底层使用netty_http,执行RPC框架, 调用调度中心方法
if (CallType.SYNC == XxlRpcReferenceBean.this.callType) {
// 构建xxlRpc 回调的结果对象
futureResponse = new XxlRpcFutureResponse(XxlRpcReferenceBean.this.invokerFactory, xxlRpcRequest, (XxlRpcInvokeCallback)null);

                        Object var31;
                        try {
                            XxlRpcReferenceBean.this.client.asyncSend(finalAddress, xxlRpcRequest);

// 得到返回结果对象
XxlRpcResponse xxlRpcResponse = futureResponse.get(XxlRpcReferenceBean.this.timeout, TimeUnit.MILLISECONDS);
if (xxlRpcResponse.getErrorMsg() != null) {
throw new XxlRpcException(xxlRpcResponse.getErrorMsg());
}
// 返回结果
var31 = xxlRpcResponse.getResult();
} catch (Exception var21) {
XxlRpcReferenceBean.logger.info(">>>>>>>>>>> xxl-rpc, invoke error, address:{}, XxlRpcRequest{}", finalAddress, xxlRpcRequest);
throw (Throwable)(var21 instanceof XxlRpcException ? var21 : new XxlRpcException(var21));
} finally {
futureResponse.removeInvokerFuture();
}

                        return var31;
                    } else if (CallType.FUTURE == XxlRpcReferenceBean.this.callType) {
                        futureResponse = new XxlRpcFutureResponse(XxlRpcReferenceBean.this.invokerFactory, xxlRpcRequest, (XxlRpcInvokeCallback)null);

                        try {
                            XxlRpcInvokeFuture invokeFuture = new XxlRpcInvokeFuture(futureResponse);
                            XxlRpcInvokeFuture.setFuture(invokeFuture);
                            XxlRpcReferenceBean.this.client.asyncSend(finalAddress, xxlRpcRequest);
                            return null;
                        } catch (Exception var20) {
                            XxlRpcReferenceBean.logger.info(">>>>>>>>>>> xxl-rpc, invoke error, address:{}, XxlRpcRequest{}", finalAddress, xxlRpcRequest);
                            futureResponse.removeInvokerFuture();
                            throw (Throwable)(var20 instanceof XxlRpcException ? var20 : new XxlRpcException(var20));
                        }
                    } else if (CallType.CALLBACK == XxlRpcReferenceBean.this.callType) {
                        XxlRpcInvokeCallback finalInvokeCallback = XxlRpcReferenceBean.this.invokeCallback;
                        XxlRpcInvokeCallback threadInvokeCallback = XxlRpcInvokeCallback.getCallback();
                        if (threadInvokeCallback != null) {
                            finalInvokeCallback = threadInvokeCallback;
                        }

                        if (finalInvokeCallback == null) {
                            throw new XxlRpcException("xxl-rpc XxlRpcInvokeCallback(CallType=" + CallType.CALLBACK.name() + ") cannot be null.");
                        } else {
                            XxlRpcFutureResponse futureResponsex = new XxlRpcFutureResponse(XxlRpcReferenceBean.this.invokerFactory, xxlRpcRequest, finalInvokeCallback);

                            try {
                                XxlRpcReferenceBean.this.client.asyncSend(finalAddress, xxlRpcRequest);
                                return null;
                            } catch (Exception var19) {
                                XxlRpcReferenceBean.logger.info(">>>>>>>>>>> xxl-rpc, invoke error, address:{}, XxlRpcRequest{}", finalAddress, xxlRpcRequest);
                                futureResponsex.removeInvokerFuture();
                                throw (Throwable)(var19 instanceof XxlRpcException ? var19 : new XxlRpcException(var19));
                            }
                        }
                    } else if (CallType.ONEWAY == XxlRpcReferenceBean.this.callType) {
                        XxlRpcReferenceBean.this.client.asyncSend(finalAddress, xxlRpcRequest);
                        return null;
                    } else {
                        throw new XxlRpcException("xxl-rpc callType[" + XxlRpcReferenceBean.this.callType + "] invalid");
                    }
                } else {
                    throw new XxlRpcException("xxl-rpc reference bean[" + className + "] address empty");
                }
            }
        }
    });
}

通过测试,查看注册的代码走向
1

实际还是调用 AdminBizImpl .registry方法。
如何实现自我注册

最简单的方式:
设置RegistryParam对象属性,
将admin所在机器的地址与配置文件中端口号,配置文件中xxl.job.executor.appname的属性注入其中。
然后调用AdminBizImpl.registry(RegistryParam)方法即可
总结

执行器注册流程如下:

  1. init JobHandler Repository
  2. refresh GlueFactory
  3. super start
    init logpath
    init invoker, admin-client 利用反射,向注册中心注册自己,并将adminBiz缓存起来
    init JobLogFileCleanThread 处理jobLog日志
    init TriggerCallbackThread 处理 触发周期性 回调, callback 和 retry
    init executor-server initRpcProvider 启动serviceRegister注册
    init, provider factory (ExecutorServiceRegistry)
    add services 将该执行器以服务的形式加入
    start 会利用netty 开启一个server, port: 9999,
    还会开启有一个ExecutorRegistryThread线程,不断地注册自己

问题: 自我注册成功, 但是注册之前的执行器丢失, 而且新注册的执行器无法显示

作者:Gavin_Alison
链接:https://www.jianshu.com/p/d70b78a704e5
来源:简书

posted @ 2020-05-29 13:27  郁闷客  阅读(3032)  评论(0)    收藏  举报