说明:到写文章的这一刻为止我用的是2.3.0版本,并且只正对springboot做说明其他没研究,有需要的自行解决。
原理图
据我在源码中查看依赖并没有发现有jetty不知道这个架构原理图对不对。
主要流程为:
server:
1.配置执行器(就是一个客户端按appname区分,比如同样的服务启动了多个实例,那么执行器就是一个,如果启动的实例名称不同,那么执行器就不同)
2.创建任务-指定执行器-指定cron-指定任务的处理方法(其实就是客户端的带有@XxlJob的方法),其他参数自行选择
client:
1.导入core包(必须)
2.做好配置后创建具体的执行任务处理类
3.如示例代码中:
一定要是给spring代理的bean,并且具体的执行方法上必须要有@XxlJob标签。
之后就可以正常执行了。
原理解析:
一、注册
基于quartz实现任务调度管理,怎样去查找任务的我也没看,看着源码挺多,比较复杂。就说说是如何接受注册的。
server端会暴露出接口ip:port/api/(uri),这个接口提供给客户端让客户端发送自己的服务地址。
服务端判断出是registry,然后将参数交给adminBiz,其实现类为AdminBizImpl,这个要注意,client哪个实现是给客户端使用的。
然后服务端中获取到JobRegisterHelper的实例,使用线程池进行注册。
注册的主要方法是XxlJobRegistryDao的save方法。
总结来说就是,客户端发送自己的实例信息给服务端,服务端只是对其客户端信息进行数据库存储,并实时监听其状态,如果退出了,则需要进行剔除,仅此而已。
那么客户端在注册阶段做了哪些事情:
客户端在启动的时候会获取配置文件中配置的服务端信息,并调用AdminBizClient中的registry方法将自己的信息发送给服务端。客户端的初始化是在XxlJobSpringExecutor中实现的,这个类实现了SmartInitializingSingleton并重写了afterSingletonsInstantiated方法。
经过调用start()之后服务端就会接受到客户端执行器信息并保存,至此注册完成。
二、初始化
服务端初始化就是加载数据信息,创建监听、任务等,这个我没看,有兴趣的可以看下。
客户端初始化时不仅仅要注册它还要加载客户端中实现的任务处理器。也就是之前图中的具体任务执行方法扫描,那么他是怎么做的。
首先SmartInitializingSingleton的afterSingletonsInstantiated方法在当前服务加载完所有的单例后会被回调,这里客户端加入了注册和扫描执行方法,具体看下执行方法的扫描
initJobHandlerMethodRepository(applicationContext),传入当前环境的上下文,
方法执行时会从上下文中先获取所有的bean,然后经过MethodIntrospector.selectMethods()方法将bean中带有@XxlJob的方法信息(主要是名称)存储到XxlJobExecutor的jobHandlerRepository中,那么以后使用的时候就从jobHandlerRepository获取。
至此,客户端的初始化完成,不过扫描bean是在注册之前,因为在注册那边说过了,就不说了。
三、执行
server端在初始化的时候加载到了自己库中register的信息,然后使用quartz调度,那么是怎么调度的。server端对调度器的管理我没看,有兴趣的可以看下,这里只说调度器是如果调度任务的。
服务端初始化时会将数据库的数据加载,并将设置的任务信息使用JobTriggerPoolHelper.trigger()添加到运行环境,添加完成后再钓鱼呢XxlJobTrigger.trigger()执行任务调度。
这个方法中会调用一个重要的方法processTrigger()这里会使用获取到的执行信息,执行runExecutor(),这个就是真正的调用执行方法了,先使用XxlJobSchduler获取到执行器ExecutorBiz这里的实现是ExecutorBizClient这个要注意,再调用其run(参数中包含执行的地址,方法名等重要参数)
run里面会直接调用postBody(),postBody()这个方法在客户端注册的时候也会用到只是参数不一样,这里发的/run,而且可以看出用的是httpurlconnection,现在服务端和客户端建立连接,连接地址为客户端ip+port+/run
客户端netty建立连接,之后,接受服务端的postBody()的requestBody数据,这个数据就是具体执行任务的方法等信息。
客户端接受参数,再根据路径run,进行下一步处理。
客户端处理:这里的处理就是BIzImpl,之后会根据参数创建tread并提交到队列等待执行。
根据type创建handler
添加到执行队列,其中包含了handler信息,这个handler其实就是我们在创建客户端时使用@XxlJob对应的方法。
后面就是线程创建,启动线程,按job信息获取执行的方法。
至此主要的执行流程分析完毕,里面还有很多调度,线程等细节,有兴趣的自己可以再debug看看。
总结一下执行:server的调度管理-到了调度时间-获取注册信息-postBody与客户端连接-发送调用的方法信息-客户端接受信息-创建handler线程-映射方法执行