一、 结构
前面六章基本上已经把调度器的部分覆盖了,接下来我们解读执行器部分,也就是xxl-job-core包。
目录 | 说明 |
---|---|
biz | 调度器与执行器交互的接口与实现 |
enums | 相关枚举 |
executor | 执行器实例以及执行器与spring的嵌合 |
glue | java动态加载的实现与其他胶水代码的枚举定义 |
handler | IJobHandler以及它的特定实现类。 |
log | 日志自定义实现,将日志写入本地文件保存 |
server | netty服务器实现,用于与调度器通信 |
thread | 任务线程,注册线程,日志文件清理线程等。 |
util | 工具类 |
二、 启动流程
XxlJobExecutor是执行器的核心启动类。
xxl-job默认支持spring集成,spring体系下不需要额外的操作。同时也提供了一些其他的框架集成实现,放在了xxl-job-executor-samples中:
我们这里只关注spring方式启动。
-
XxlJobSpringExecutor.afterSingletonsInstantiated()
XxlJobSpringExecutor使用了SmartInitializingSingleton而非InitializingBean来进行初始化。SmartInitializingSingleton是在spring容器中所有bean加载完成后,才会被调用,这里主要是为了保证JobHandler已经spring容器加载
。
-
第一步,将业务系统@XxlJob注解了的方法加载成JobHandler实例,保存到一个本地Map对象中(代码无亮点,不再展开,关于spring的部分以后开个spring源码系列再来唠)。
-
第二步,加载Glue代码工厂实例,用于做运行中动态代码加载,此部分放在下面第三章详解。
-
第三步,进入XxlJobExecutor启动主流程。
-
XxlJobExecutor.start()
-
第一步,初始化任务处理日志的路径目录初始化,值得一提这里的默认base路径不适用于windwos需要重新设定:
-
第二步,初始化调度器,xxl-job 的调度器原来支持多节点部署,是我肤浅了。
-
第三步,启动日志文件清理线程,文件清理周期由用户指定,logRetentionDays=1代表清理一天前的日志文件。
-
第四步,启动回调线程,这里值得一提,我们知道xxl-job的任务是通过调度器下发给执行器的,而当执行器执行完任务之后,会将执行结果存放在一个queue中。然后由这个回调线程不断的将queue中的结果返还给调度器。
-
第五步,启动内嵌服务器EmbedServer。
-
XxlJobExecutor.initEmbedServer()
-
第一步,寻找一个可用的端口,默认先使用9999,这里值得一提的是找可用端口的代码:
从9999开始,往下递减,判断可用的方法则是直接使用java.net.ServerSocket实例化,抛异常说明已经被占用了。
-
第二步,拼接了一个http协议的请求地址。
-
第三步,启动netty服务器。
netty服务器的作用是与调度器进行通信,相关的具体配置,我们下一章节再结合netty进行讲解。
三、 动态代码执行
Glue=胶水,胶水代码这个词还是挺贴切的。
xxl-job支持的胶水代码主要是两部分,JVM类代码和脚本语言代码。
脚本代码的执行
脚本代码的执行与glue包没什么关系,我们从任务执行的一段代码中找到相关部分的截出来。
首先判断判断是否是脚本代码,最后使用脚本代码生成了一个ScriptJobHandler对象,重点就在这里。
-
ScriptJobHandler.execute()
-
第一步,获取cmd,这里的cmd见第三章的枚举图,cmd即为各种脚本语言的执行器,
也即执行器本地必须安装了相关的脚本执行器才可以执行相关脚本。
-
第二步,将脚本保存成一个本地文件,准备之后直接用执行器执行。
-
第三步,获取到前文提到的日志文件地址。
-
第四步,对广播分片模式的支持(广播分片模式见前文【xxl-job源码阅读——(五)快慢线程池与负载策略解析】)
-
第五步,使用Java.lang.Runtime执行命令。
这里还有个面试常见题,join()。
JVM类的执行
Groovy也是基于JVM的语言,类似的还有Scala,虽然语法比java精简,但是易读性可能会差一些。
之前我看Scala代码与人讨论,得出一个结论,Scala资深大神写的代码,只有大神自己能看懂╮( ̄▽  ̄)╭。
xxl支持的JVM类代码,其实也只是java与groovy,因为这里直接使用了GroovyClassLoader作为类加载器。
-
Glue工厂类的初始化
SpringGlueFactory是GlueFactory的子类,在前文的执行器启动过程中,Spring框架下加载的,是SpringGlueFactory。 -
SpringGlueFactory
相较于GlueFactory只是多了一个方法——injectService,看方法名字也能明白,作用是将一个object注入到spring容器中,作为一个bean存在。
-
GlueFactory
核心的主要是GroovyClassLoader与一个代码加载方法,
-
第一步,通过GroovyClassLoader编译class,
-
第二步,通过class反射实例化一个object。
-
第三步,将object注入到spring容器中。
到此结束,看过类加载器相关面试题的话这部分还是比较好理解的。
另外,动态代码加载也不只是GroovyClassLoader这一种方式,使用JDK中的tools.jar一样可以做到这个功能,当然就只支持java语法了,有兴趣的同学可以看我以前写的这一篇:
[JAVA代码的动态编译加载,随后实例化bean注入Spring容器
]:
https://blog.csdn.net/qq_35946969/article/details/117453470