xxl-job源码学习之执行器

xxl-job源码结构

日志

在这里插入图片描述

17:28:40.711 logback [main] INFO  c.x.j.e.core.config.XxlJobConfig - >>>>>>>>>>> xxl-job config init.
17:28:40.720 logback [main] INFO  c.x.job.core.executor.XxlJobExecutor - >>>>>>>>>>> xxl-job register jobhandler success, name:commandJobHandler, jobHandler:com.xxl.job.executor.service.jobhandler.CommandJobHandler@144ab54
17:28:40.721 logback [main] INFO  c.x.job.core.executor.XxlJobExecutor - >>>>>>>>>>> xxl-job register jobhandler success, name:demoJobHandler, jobHandler:com.xxl.job.executor.service.jobhandler.DemoJobHandler@2cfa2c4f
17:28:40.721 logback [main] INFO  c.x.job.core.executor.XxlJobExecutor - >>>>>>>>>>> xxl-job register jobhandler success, name:httpJobHandler, jobHandler:com.xxl.job.executor.service.jobhandler.HttpJobHandler@6ecab872
17:28:40.721 logback [main] INFO  c.x.job.core.executor.XxlJobExecutor - >>>>>>>>>>> xxl-job register jobhandler success, name:shardingJobHandler, jobHandler:com.xxl.job.executor.service.jobhandler.ShardingJobHandler@48eb9836
17:28:40.740 logback [main] INFO  c.x.r.r.p.XxlRpcProviderFactory - >>>>>>>>>>> xxl-rpc, provider factory add service success. serviceKey = com.xxl.job.core.biz.ExecutorBiz, serviceBean = class com.xxl.job.core.biz.impl.ExecutorBizImpl
17:28:41.019 logback [main] INFO  o.s.w.s.m.m.a.RequestMappingHandlerAdapter - Looking for @ControllerAdvice: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@5cdec700: startup date [Thu Aug 01 17:28:39 CST 2019]; root of context hierarchy
17:28:41.066 logback [main] INFO  o.s.w.s.m.m.a.RequestMappingHandlerMapping - Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
17:28:41.067 logback [main] INFO  o.s.w.s.m.m.a.RequestMappingHandlerMapping - Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
17:28:41.094 logback [main] INFO  o.s.w.s.h.SimpleUrlHandlerMapping - Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
17:28:41.095 logback [main] INFO  o.s.w.s.h.SimpleUrlHandlerMapping - Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
17:28:41.126 logback [main] INFO  o.s.w.s.h.SimpleUrlHandlerMapping - Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
17:28:41.223 logback [Thread-8] INFO  com.xxl.rpc.remoting.net.Server - >>>>>>>>>>> xxl-rpc remoting server start success, nettype = com.xxl.rpc.remoting.net.impl.netty_http.server.NettyHttpServer, port = 9999
17:28:41.300 logback [main] INFO  o.s.j.e.a.AnnotationMBeanExporter - Registering beans for JMX exposure on startup
17:28:41.308 logback [main] INFO  o.a.coyote.http11.Http11NioProtocol - Starting ProtocolHandler ["http-nio-9002"]
17:28:41.309 logback [main] INFO  o.a.tomcat.util.net.NioSelectorPool - Using a shared selector for servlet write/read
17:28:41.321 logback [main] INFO  o.s.b.c.e.t.TomcatEmbeddedServletContainer - Tomcat started on port(s): 9002 (http)

执行器模块启动流程

  1. XxlJobConfig 配置初始化并且实例化bean XxlJobExecutor
@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;
}

@Bean(initMethod = “start”, destroyMethod = “destroy”)此处指明bean初始化时触发start方法

  1. XxlJobSpringExecutor 调用start()方法
public class XxlJobSpringExecutor extends XxlJobExecutor implements ApplicationContextAware {
    @Override
    public void start() throws Exception {
        //初始化作业处理器仓库
        initJobHandlerRepository(applicationContext);
        // refresh GlueFactory
        GlueFactory.refreshInstance(1);
        //调用父类XxlJobExecutor的start方法
        super.start();//[4]
    }
    private void initJobHandlerRepository(ApplicationContext applicationContext){
        if (applicationContext == null) {
            return;
        }
        //初始化作业处理器
        //获取spring通过注解注册的bean实例,并从中取得作业handler并注册
        Map<String, Object> serviceBeanMap = applicationContext.getBeansWithAnnotation(JobHandler.class);
        if (serviceBeanMap!=null && serviceBeanMap.size()>0) {
            for (Object serviceBean : serviceBeanMap.values()) {
                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.");
                    }
                    //注册作业handler,该方法继承自XxlJobExecutor
                    registJobHandler(name, handler);//[3]
                }
            }
        }
    }
}
  1. registJobHandler(name, handler)
XxlJobExecutor.java
//存储jobhandler
private static ConcurrentMap<String, IJobHandler> jobHandlerRepository 
= new ConcurrentHashMap<String, IJobHandler>();

//注册handler,即把jobhandler实例存储
public static IJobHandler registJobHandler(String name, IJobHandler jobHandler){
	logger.info(">>>>>>>>>>> xxl-job register jobhandler success, name:{}, jobHandler:{}",
	 name, jobHandler);
	return jobHandlerRepository.put(name, jobHandler);
}
  1. XxlJobSpringExecutor 在start()方法中super.start(),触发XxlJobExecutor的start()方法。
XxlJobExecutor.java
public void start() throws Exception {
    //日志文件路径
    XxlJobFileAppender.initLogPath(logPath);
    //初始化RPC调用者,调度中心客户端,adminAddresses可能为多个地址即多个调度中心机器。
    initAdminBizList(adminAddresses, accessToken);//[5]
    //启动日志文件清理线程
    JobLogFileCleanThread.getInstance().start(logRetentionDays);
    //初始化触发器回调线程
    TriggerCallbackThread.getInstance().start();
    //初始化RPC提供服务者
    port = port>0?port: NetUtil.findAvailablePort(9999);
    ip = (ip!=null&&ip.trim().length()>0)?ip: IpUtil.getIp();
    initRpcProvider(ip, port, appName, accessToken);//[3]
}
  1. initAdminBizList(adminAddresses, accessToken) 初始化RPC调用者列表,即调度中心机器。
//XxlJobExecutor.java
private static List<AdminBiz> adminBizList;
private static Serializer serializer;
private void initAdminBizList(String adminAddresses, String accessToken) throws Exception {
    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) {
                String addressUrl = address.concat(AdminBiz.MAPPING);
                //new XxlRpcReferenceBean(...).getObject()
                //动态代理,获取AdminBiz接口的实例对象
                AdminBiz adminBiz = (AdminBiz) new XxlRpcReferenceBean(
                        NetEnum.NETTY_HTTP,
                        serializer,
                        CallType.SYNC,
                        LoadBalance.ROUND,
                        AdminBiz.class,
                        null,
                        3000,
                        addressUrl,
                        accessToken,
                        null,
                        null
                ).getObject();
                if (adminBizList == null) {
                    adminBizList = new ArrayList<AdminBiz>();
                }
                adminBizList.add(adminBiz);
            }
        }
    }
 }
package com.xxl.rpc.remoting.invoker.reference;
XxlRpcReferenceBean.java
//动态代理,所有动态代理类的方法调用,都会交由InvocationHandler接口实现类里的invoke()方法去处理,
invoke()方法由rpc包的方法处理并放回对象
public Object getObject() {
	return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), 
	new Class[]{this.iface}, 
	new InvocationHandler() {...});
}

//返回指定接口的代理类的实例,该接口将方法调用分派给指定的调用处理程序。
@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)

参考链接:Java的动态代理(dynamic proxy)

  1. initRpcProvider(ip, port, appName, accessToken)
    初始化RPC服务提供者xxlRpcProviderFactory
XxlJobExecutor.java
private void initRpcProvider(String ip, int port, String appName, String accessToken) throws Exception {
	// init, provider factory
	String address = IpUtil.getIpPort(ip, port);
	Map<String, String> serviceRegistryParam = new HashMap<String, String>();
	serviceRegistryParam.put("appName", appName);
	serviceRegistryParam.put("address", address);
	
	xxlRpcProviderFactory = new XxlRpcProviderFactory();
	xxlRpcProviderFactory.initConfig(NetEnum.NETTY_HTTP, Serializer.SerializeEnum.HESSIAN.getSerializer(), ip, port, accessToken, ExecutorServiceRegistry.class, serviceRegistryParam);
	
	// add services
	xxlRpcProviderFactory.addService(ExecutorBiz.class.getName(), null, new ExecutorBizImpl());
	
	// start
	xxlRpcProviderFactory.start();
}
xxlRpcProviderFactory.java
public void addService(String iface, String version, Object serviceBean) {
    String serviceKey = makeServiceKey(iface, version);
    this.serviceData.put(serviceKey, serviceBean);
    logger.info(">>>>>>>>>>> xxl-rpc, provider factory add service success. serviceKey = {}, serviceBean = {}", serviceKey, serviceBean.getClass());
}
xxlRpcProviderFactory.java
public void start() throws Exception {
    this.serviceAddress = IpUtil.getIpPort(this.ip, this.port);
    //生成Server实例 NettyHttpServer
    this.server = (Server)this.netType.serverClass.newInstance();
    //设置NettyHttpServer开始的回调服务
    this.server.setStartedCallback(new BaseCallback() {
        public void run() throws Exception {
            if (XxlRpcProviderFactory.this.serviceRegistryClass != null) {
                XxlRpcProviderFactory.this.serviceRegistry = 
                (ServiceRegistry)XxlRpcProviderFactory.this.serviceRegistryClass.newInstance();
                XxlRpcProviderFactory.this.serviceRegistry.start(XxlRpcProviderFactory.this.serviceRegistryParam);
                if (XxlRpcProviderFactory.this.serviceData.size() > 0) {
                	XxlRpcProviderFactory.this.serviceRegistry.registry(XxlRpcProviderFactory.this.serviceData.keySet(),
                	XxlRpcProviderFactory.this.serviceAddress);
                }
            }

        }
    });
    //设置NettyHttpServer停止事件的回调服务
    this.server.setStopedCallback(new BaseCallback() {
        public void run() {
            if (XxlRpcProviderFactory.this.serviceRegistry != null) {
                if (XxlRpcProviderFactory.this.serviceData.size() > 0) {
                    XxlRpcProviderFactory.this.serviceRegistry.remove(XxlRpcProviderFactory.this.serviceData.keySet(), XxlRpcProviderFactory.this.serviceAddress);
                }
                XxlRpcProviderFactory.this.serviceRegistry.stop();
                XxlRpcProviderFactory.this.serviceRegistry = null;
            }

        }
    });
    //NettyHttpServer
    this.server.start(this);
}
  1. com.xxl.rpc.remoting.net.Server - >>>>>>>>>>> xxl-rpc remoting server start success, nettype =com.xxl.rpc.remoting.net.impl.netty_http.server.NettyHttpServer, port = 9999
    远程连接服务器启动成功,NettyHttpServer服务器端口为9999
    执行器实际上是一个内嵌的Server,默认端口9999(配置项:xxl.job.executor.port)。

  2. 上述xxlRpcProviderFactory.start()中调用了静态类ExecutorServiceRegistry的start()方法

public static class ExecutorServiceRegistry extends ServiceRegistry {
       @Override
       public void start(Map<String, String> param) {
           //启动执行器注册线程
           ExecutorRegistryThread.getInstance().start(param.get("appName"), param.get("address"));
       }
       //...
}
  1. 执行器注册线程
ExecutorRegistryThread.java
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() {
            // 注册
            while (!toStop) {
                try {
                    RegistryParam registryParam = 
                    new RegistryParam(RegistryConfig.RegistType.EXECUTOR.name(), appName, address);
                    for (AdminBiz adminBiz: XxlJobExecutor.getAdminBizList()) {
                        try {
                        	//注册 adminBiz.registry(registryParam)
                            ReturnT<String> 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 {
                    TimeUnit.SECONDS.sleep(RegistryConfig.BEAT_TIMEOUT);
                } catch (InterruptedException e) {
                    logger.warn(">>>>>>>>>>> xxl-job, executor registry thread interrupted, error msg:{}", e.getMessage());
                }
            }
            
            try {
                RegistryParam registryParam = new RegistryParam(RegistryConfig.RegistType.EXECUTOR.name(), appName, address);
                for (AdminBiz adminBiz: XxlJobExecutor.getAdminBizList()) {
                    try {
                    	// 注册移除
                        ReturnT<String> 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();
}
  1. 上述线程中调用AdminBiz接口在调度中心中的实现类AdminBizImpl的registry、registryRemove方法更新数据库中xxl_job_registry表(执行器注册表,维护在线的执行器和调度中心机器地址信息)
package com.xxl.job.admin.service.impl;
AdminBizImpl.java
@Override
public ReturnT<String> registry(RegistryParam registryParam) {
	//registryUpdate
	int ret = xxlJobRegistryDao.registryUpdate(registryParam.getRegistGroup(), 
	registryParam.getRegistryKey(), 
	registryParam.getRegistryValue());
    if (ret < 1) {
    	//registrySave
        xxlJobRegistryDao.registrySave(registryParam.getRegistGroup(), 
        registryParam.getRegistryKey(), 
        registryParam.getRegistryValue());
    }
    return ReturnT.SUCCESS;
}

@Override
public ReturnT<String> registryRemove(RegistryParam registryParam) {
	//registryDelete
    xxlJobRegistryDao.registryDelete(registryParam.getRegistGroup(), 
    registryParam.getRegistryKey(), 
    registryParam.getRegistryValue());
    return ReturnT.SUCCESS;
}

你可能感兴趣的:(中间件,xxl-job源码学习)