手写spring-boot-devtools(二):手写mini版(附源码)

文章涉及的源码均已上传到了码云,参考【README.md】文件部署运行即可
手写系列码云地址: git@gitee.com:tangjingshan/tjs-study-mini.git
本文代码路径:{@link tjs.styudy.mini.demo.devtools.DemoDevtoolsApplication#main}

前言

本文主要是总结下如何手写spring-boot-devtools的mini版本,至于其具体的源码实现,可以参考之前的博客
手写spring-boot-devtools(一):手把手解析源码(配gif动态图)

一. 如何运行demo

  1. 引入文章开头中的码云项目
  2. 运行测试类tjs.styudy.mini.demo.devtools.DemoDevtoolsApplication#main
    image.png
  3. 运行结果动态图
    devtoos-mini-demo演示.gif

二. 分析待做事项

通过上一篇博客的分析,可知spring-boot-devtools主要由三部分组成

  1. 监听springboot启动事件 -> 重启
  2. 文件监听器 -> 清理资源 -> 重启
  3. 自定义类加载器

三. 开始手写

接下来就按着这三个大方向,开始手写
具体的手写代码见码云项目,代码量较多这里就不贴了
这里就贴一下关键节点的代码位置

/**
 ** 1. 监听springboot启动事件 -> 重启
 * 事件:{@link tjs.styudy.mini.springboot.devtools.config.RestartApplicationListener#onApplicationStartingEvent(org.springframework.boot.context.event.ApplicationStartingEvent)}
 * 重启:{@link tjs.styudy.mini.springboot.devtools.config.Restarter#immediateRestart()}
 *
 ** 2. 文件监听器 -> 清理资源 -> 重启
 * 监听器:{@link tjs.styudy.mini.springboot.devtools.fileWatch.FileSystemWatcher#start(long, java.lang.String)}
 * 清理资源: {@link tjs.styudy.mini.springboot.devtools.config.Restarter#stop()}
 * 重启: {@link tjs.styudy.mini.springboot.devtools.config.Restarter#immediateRestart()}
 *
 ** 3. 自定义类加载器
 * 类加载器: {@link tjs.styudy.mini.springboot.devtools.config.RestartClassLoader#loadClass(java.lang.String, boolean)}
 * */

三. 遇到的问题

1. ApplicationStartingEvent无效

ApplicationStartingEvent是在spring收集事件订阅者之前发布的,发布时还没开开始扫描bean,所以使用@Compent注解这种形式,是无法成功订阅该事件的
所以可以借助spring的SPI机制,在spring.factories存入目标监听器RestartApplicationListener
image.png

2. 未结束首次调用main方法的线程

由于未结束首次调用main方法的线程,导致ioc加载了多次而报错。
如何结束呢?spring-boot-devtools是在org.springframework.boot.devtools.restart.Restarter#immediateRestart以抛出自定义异常的形式结束
image.png
在以下位置捕获自定义异常了,捕获后不做任何处理
image.png
对应的mini版中的类如下

* 自定义退出异常:{@link tjs.styudy.mini.springboot.devtools.config.SilentExitExceptionHandler.SilentExitException}
* 自定义退出异常-捕获:{@link tjs.styudy.mini.springboot.devtools.config.SilentExitExceptionHandler#uncaughtException(java.lang.Thread, java.lang.Throwable)}

3. 未正确清理资源,导致重启抛出各种异常

由于RestartClassLoader类加载器只重新加载工作路径的类,其他的类依然是由AppClassLoader或其他默认加载器加载,那第三方jar包程序中经常会用到的静态变量等,就必须要手动清除点,否则就会因为重复加载而报错
这段清理逻辑牵扯太多,mini直接复制的spring-boot-devtools的实现

清理资源: {@link org.springframework.boot.devtools.restart.Restarter#stop()}

4. FileAlterationMonitor如何获取所有变化的文件

mini版本的文件监听是基于commons-io实现的,其并未提供获取所有变化文件的方法
观看其源码可以发现,它注册的Listener监听器是不会重复new的,所以可以在extends FileAlterationListenerAdaptor的监听器实现类,新增一个集合的成员属性,在文件变更时放入集合中,具体代码如下

image.png

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值