SpingBoot的5个扩展点,超级实用!


  • 1、初始化器ApplicationContextInitializer
  • 2、监听器ApplicationListener
  • 3、Runner
  • 4、BeanFactoryPostProcessor
  • 5、BeanPostProcessor
  • 后记


1、初始化器ApplicationContextInitializer

我们在启动Spring Boot项目的时候,是执行这样一个方法来启动的

我们一层一层往下点,最终发现执行的是这个方法

所以我们在启动项目的时候也可以这样启动 new SpringApplication(SpringbootExtensionPointApplication.class).run(args); 老的只是包装了一个静态方法,实际底层就是实例化一个SpringApplication对象,然后调用它的run方法。

我们进到构造方法里看下,红框里面标出来的,一个是设置初始化器,一个是设置监听器。

点进去看下,这两个底层调的方法是一样,就是传入一个类型,通过Spring SPI的方式查找这个类型的实现类

打个断点,启动一下,此时有7个上下文初始器,这是系统自带的,配置在不同的spring.factories文件中。

现在我要新建一个自己的初始化器

此时为了能够让Spring Boot在启动的时候能够扫描到我创建的初始化器应该怎么办?就是在spring.factories文件中添加一下,注册一下,这样就能扫描到,这个就是SPI。SPI 全称为 Service Provider Interface,是一种服务发现机制。

那么这时候我们再启动一下Spring Boot,发现自己创建的ApplicationContextInitializer也已经注册上来了,变成8个了。

把断点放掉,在控制台中也打印出了这句话,那么这个就是第一个扩展点ApplicationContextInitializer

定义了这8个初始化器,那一定是有地方在调它们的,不然怎么会打印出来呢,那具体在什么地方调的,我们在自己的初始化器的地方打断点,看到已经进来了,然后看下方的堆栈信息,这个就是调用的地方。

原来是调用了run()方法中的prepareContext()方法中的applyInitializers()方法,在这个方法中for循环的调用各个初始化器的initialize()方法,从而我们就能看到把Jack的ApplicationContextInitializer这句话给打印出来了。

那么这个查找的方法就是以结果为导向来反查调用方,因为你正查的话是很难找到,很难记住的,这个方法希望大家学习到。

那么最后来看下我们第一个扩展点所处的位置

初始化器可以做一些事情,比如Environment对象设置一些变量配置。

2、监听器ApplicationListener

在上面构造函数里我们发现除了有setInitializers,还有setListeners,那么这个listeners其实也是一个扩展点。

那么什么是监听器,就是这样的,这个其实就是观察者模式,ApplicationEventMulticaster发布事件,各个Listener监听事件。

和初始化器一样,现在我们自定义两个监听器,一个是Starting,一个是Started,括号里面的是泛型,这个是一定要写的,如果不写的话就是不管什么类型的Event都会监听。

这个泛型是上限为ApplicationEvent类型的Event,具体的实现类有很多个,Starting和Started只是其中两个。

现在我们还是把这两个监听器通过SPI的方式加到配置中去

好,运行一下,我们看到这两句话已经打印出来了

和监听器一样,既然能够打印出来,那肯定是有地方在调用,所以我们在JackStartingApplicationListener打个断点,然后看下堆栈信息

我们可以看到在SpringApplication run()方法的listeners.starting()开始进去发送ApplicationStartingEvent广播事件,最后发布出去,由我们自己编写的事件监听器接收到。

那么ApplicationStartedEvent事件也是一样的道理,通过打断点的方式来找到它的调用方,最后我们再来看下此时的扩展点图

3、Runner

我们看到在listeners.started()后面有个callRunners

我们点进去看下,它其实就是从容器中获取两种类型的Runner,一种是ApplicationRunner,还有一种是CommandLineRunner,然后for循环的对它们进行调用,那么其实这个也是一个扩展点

我们来写一个自己的Runner

运行一下,看下打印出来了

那么这个Runner的一般应用场景就是资源释放清理或者做注册中心,因为执行到Runner的时候项目已经启动完毕了,这时候就可以注册到注册中心上去了。此时我们再看下扩展点图。

4、BeanFactoryPostProcessor

我们看下run方法里的refreshContext()方法

这个方法底层会调spring里面的refresh()方法,这个方法里面就会做对容器的初始化。红框里的invokeBeanFactoryPostProcessors()方法,这里也有一个扩展点,就是BeanFactoryPostProcessor,执行对BeanFactory的后置处理。Spring Boot解析配置成BeanDefinition的操作也是在此方法中。

现在我们来创建一个自己的BeanFactoryPostProcessor,这个方法里面可以修改beanFactory的属性,beanfactory里面有BeanDefinition,可以修改BeanDefinition里面的值。BeanDefinition是一个bean的元数据的信息,有多少个bean就有多少个BeanDefinition

运行一下,也打印出来了

此时我们再看下扩展点图,越来越完善了。

5、BeanPostProcessor

最后介绍的是BeanPostProcessor,它在通过反射构造函数进行bean实例化之后执行,那么红框里面标出来的registerBeanPostProcessors()方法就是向BeanFactory中注册beanpostprocessor,用于后续bean创建的拦截操作。

现在我们来创建一个自己的BeanPostProcessor,一共有两个方法,postProcessBeforeInitializationpostProcessAfterInitialization,不过我们一般用postProcessAfterInitialization,在bean调用反射构造函数实例化之后执行。著名的应用场景AOP底层就是通过BeanPostProcessor来实现的。

现在我在postProcessAfterInitialization上打个断点,看下堆栈信息是在哪里调用的

是在finishBeanFactoryInitialization()方法处调用的

后记

最后我来把扩展点图补充完整,如下所示,很清晰明了,在什么时候调用了什么,我们自己开发的时候结合应用场景,在什么时候要干什么事,就知道要创建什么类型的扩展点了。

本文前三个讲的是Spring Boot里面自己有的扩展点,后两个因为Spring Boot底层调的是Spring的源码,所以属于Spring里面的扩展点,所以如果这么算的话Spring里面的扩展点还有很多扩展点,比如InitializeBean、Aware等等这里都没讲,等待大家去发掘,谢谢观看 ~

程序汪资料链接

程序汪接私活项目目录,2023年总结

Java项目分享  最新整理全集,找项目不累啦 07版

欢迎添加程序汪微信 itwang007  进粉丝群

相关推荐

  • 「AI透视眼」,三次马尔奖获得者Andrew带队解决任意物体遮挡补全难题
  • 田渊栋等人新作:突破内存瓶颈,让一块4090预训练7B大模型
  • 挑战OpenAI的新模型免费上线,40%计算量性能逼近GPT-4
  • 驱动产学研深度融合,「未来高新视频智能技术中心创新联合体 」在快手揭牌
  • 清华姚班本科生连发两作,十年来最大改进:矩阵乘法接近理论最优
  • 阿里俞永福退出一线,天涯创始人称公司欠债约2亿
  • AI双雄论剑:杨植麟与朱啸虎的11大观点对决
  • 2024年上的第一当:公司说公积金10%,结果竟是个人交5%,公司交5%!
  • 北漂7年,改变我人生命运的一个女人。
  • 今日arXiv最热大模型论文:北大发布,通过上下文提示,让大模型学习一门新的语言
  • 夕小瑶科技说,招人!
  • Sora 作者被曝读博期间仅发表两篇论文,我们是否需要重塑科研价值观?
  • 重磅!中国科学院发布128个科学研究前沿
  • 贝叶斯比较
  • 【AIGC工具系列】一款AI智能编程神器
  • 博士就给编,补贴60万,考核减半!
  • 大语言模型(LLM)超全资源清单
  • GPT-4 Claude 3 Gemini Pro对决,还是GPT-4胜一筹
  • 手机、PC轻松跑大模型!谷歌发最新API,28亿参数模型本地跑
  • Figure简历数量暴涨218%;阿里云成立联盟推进大模型应用;印度政府批准1030亿卢比AI项目丨AIGC大事日报