在社区里碰到过好几次小伙伴运行的Demo报找不到注册节点的问题。经过查看发现都是对于Spring生命周期理解的问题。
LF在在Springboot自动装配过程中,对于节点的扫描和规则的初始化是不同的生命周期。正常的顺序都应该是:先注册节点再初始化规则。如果出现了先初始化规则,再注册节点,就会出现问题。
LF的Springboot的自动装配主要用到了Spring的两个生命周期。
第一个是BeanPostProcessor,这个阶段在受spring管理的bean初始化的前后,所以这个接口分为初始化前和初始化后两个实现。LF是利用了初始化后这个生命周期来对所有的组件进行初始化。这个生命周期在整个spring生命周期相对中间的位置。
第二个是SmartInitializingSingleton,这个阶段在所有受spring管理单例对象(非懒加载)初始化完成之后进行回调。LF是利用了所有的单例Bean都初始化好后这个生命周期来去解析定义好规则(包括项目内的和其他存储里的),这个生命周期在整个spring生命周期相对靠后的位置。
所以,对于普通的扫描节点来说,因为LF已经严格控制了生命周期,所以不会出现问题。
凡是出问题的场景都是使用者自己利用代码去注册节点/链路,但使用者没有选对正确的生命周期。
举个最简单的例子,使用者用代码方式去额外定义规则。想要在系统启动时去运行一段代码,其实方式太多了。但是如果你使用在一个bean里用@PostConstruct注解去做这件事情,就有可能出现问题。
图片
从图上可以看到,@PostConstruct这个注解是在初始化bean的过程中执行,由于bean是一个个进入BeanPostProcessor这个生命周期的,如果使用者在这个周期里去定义链路并解析,由于链路所用到的节点很可能还未被初始化好,所以这时候就会报找不到节点的错误。
正确的做法是,使用者也去定义一个类,实现SmartInitializingSingleton或者去实现CommandLineRunner,利用这两个比较靠后的生命周期去定义额外的规则。
推荐是采用更靠后的CommandLineRunner去定义,这个生命周期比SmartInitializingSingleton还要往后。非常适合用来做启动系统后的一系列自定义业务。
同理,如果你在static块中去定义规则,或是在构造方法里去定义规则,其生命周期和@PostConstruct差不多。
再比如,你在CommandLineRunner里用代码去定义额外节点。也是不行的,因为CommandLineRunner在SmartInitializingSingleton之后,等于说解析规则在注册你自己额外节点之前,如果规则里写了额外注册的节点的话,那么也会报找不到节点。
总的方针就是:规则的定义和解析一定要在节点注册之后。
在Spring中可供扩展的生命周期有很多。所以当开发者想要在系统启动时额外做一些事情,有很多种选择,但是开发者一定要清楚你的这个触发时机是在整个生命周期的哪一步。
我之前整理过整个Spring启动过程的完整生命周期图,这次我用红框标明了LF框架在注册节点和解析规则所使用的两个生命周期的相对位置。
图片
其中每一个生命周期的讲解在之前我写的一篇文章中也有详细解析,这里附上链接:
Springboot启动扩展点超详细总结,再也不怕面试官问了
LF CLUB
LF CLUB是由作者创办的高级付费社区。
LF CLUB能帮助到所有LiteFlow框架的使用者,以及想使用LiteFlow的潜在开发者。