Spring Developer Tools 源码分析:三、重启自动配置

接上文 Spring Developer Tools 源码分析:二、类路径监控
,接下来看看前面提到的这些类是如何配置,如何启动的。

spring-boot-devtools 使用了 Spring Boot 的自动配置方式,我们先关注本地开发环境中自动重启的部分。

LocalDevToolsAutoConfiguration
主要包含了 LiveReload
和重启的配置,LiveReload 后续看情况再介绍,这里先看重启的配置。

3.1 LocalDevToolsAutoConfiguration
本地配置

@Configuration
@ConditionalOnInitializedRestarter
@EnableConfigurationProperties(DevToolsProperties.class)
public class LocalDevToolsAutoConfiguration {

在这个类上 @ConditionalOnInitializedRestarter
是一个该配置生效的条件,具体实现中会判断 Restarter
是否已经实例化,并且是否存在可被监控的类目录(除 jar
文件外的目录),如果已经实例化,并且有需要监控的目录才会启动。

通过 java -jar 方式启动的时候,由于不存在需要监控的目录,devtools 不会触发后续的配置,因此虽然启动了 Restarter,但是并不会监控目录,也不会自动重启。

当通过 IDE 启动项目时,默认情况下会满足这里的条件, LocalDevToolsAutoConfiguration
中的其他配置可以生效。

3.2 RestartConfiguration 重启配置

/**
 * Local Restart Configuration.
 */
@Configuration
@ConditionalOnProperty(
    prefix = "spring.devtools.restart", 
    name = "enabled", 
    matchIfMissing = true)
static class RestartConfiguration {

RestartConfiguration
上也有限制条件,只有当设置下面的参数才不会生效

spring.devtools.restart.enabled=false

不设置或者设置为任何不是 false
(忽略大小写)的值时,都会生效。

除了这个参数能控制外,还有一个可以直接控制 Restarter 是否生效的参数,后续会介绍。

下面逐个看 RestartConfiguration
中的各个配置。

3.2.1 FileSystemWatcherFactory 文件监控

配置代码如下:

@Bean
public FileSystemWatcherFactory fileSystemWatcherFactory() {
    return this::newFileSystemWatcher;
}

private FileSystemWatcher newFileSystemWatcher() {
    Restart restartProperties = this.properties.getRestart();
    FileSystemWatcher watcher = new FileSystemWatcher(true,
            restartProperties.getPollInterval(),
            restartProperties.getQuietPeriod());
    String triggerFile = restartProperties.getTriggerFile();
    if (StringUtils.hasLength(triggerFile)) {
        watcher.setTriggerFilter(new TriggerFileFilter(triggerFile));
    }
    List<File> additionalPaths = restartProperties.getAdditionalPaths();
    for (File path : additionalPaths) {
        watcher.addSourceFolder(path.getAbsoluteFile());
    }
    return watcher;
}

FileSystemWatcherFactory
是一个函数式接口,这里直接返回了一个方法引用。将来调用该接口的方法时,就会执行下面的 newFileSystemWatcher
方法。

每次调用 fileSystemWatcherFactory()
方法时,返回的都是同一个 FileSystemWatcherFactory
,但是调用工厂的 getFileSystemWatcher()
方法时返回都是新的 FileSystemWatcher

通过这个方法可以看到创建 FileSystemWatcher
时,这里会判断是否配置了触发文件(只有修改指定文件才会重启),是否配置额外需要监控变化的位置。

3.2.2 ClassPathRestartStrategy 重启策略

代码如下:

@Bean
@ConditionalOnMissingBean
public ClassPathRestartStrategy classPathRestartStrategy() {
    return new PatternClassPathRestartStrategy(
            this.properties.getRestart().getAllExclude());
}

该方法返回了 PatternClassPathRestartStrategy
实现类,判断是否重启时,忽略所有传入的位置,默认忽略的位置如下:

private static final String DEFAULT_RESTART_EXCLUDES = "META-INF/maven/**,"
        + "META-INF/resources/**,resources/**,static/**,public/**,templates/**,"
        + "**/*Test.class,**/*Tests.class,git.properties,META-INF/build-info.properties";

额外的排除项可以通过下面的参数设置:

spring.devtools.restart.additional-exclude=

3.2.3 ClassPathFileSystemWatcher 类路径监控

代码如下:

@Bean
@ConditionalOnMissingBean
public ClassPathFileSystemWatcher classPathFileSystemWatcher() {
    URL[] urls = Restarter.getInstance().getInitialUrls();
    ClassPathFileSystemWatcher watcher = new ClassPathFileSystemWatcher(
            fileSystemWatcherFactory(), classPathRestartStrategy(), urls);
    watcher.setStopWatcherOnRestart(true);
    return watcher;
}

这里创建时,从 Restarter
获取了需要监控的类路径(后续会详细介绍),然后创建了一个 watcher
,使用了前面创建的两个 beansetStopWatcherOnRestart
的意思是当类路径发生变化并且需要重启时,是否停止类监控,这里设置了 true
,也就是重启前会停止监控。

如果重启前会停止监控,我们可能需要担心如果配置改错了导致 Spring 无法启动该怎么办,devtools 也提供了相应的策略来解决这个问题,下一小节就会看到。

3.2.3 监听 ClassPathChangedEvent

代码如下:

@EventListener
public void onClassPathChanged(ClassPathChangedEvent event) {
    if (event.isRestartRequired()) {
        Restarter.getInstance().restart(
                new FileWatchingFailureHandler(fileSystemWatcherFactory()));
    }
}

当一个方法添加 @EventListener
时,Spring 会把该方法添加到事件监听中,当触发该事件时,这个方法就会被调用。在上一篇介绍了 ClassPathChangedEvent
,其中包含了 restartRequired
,这里会判断是否需要重启,当需要重启时,就会调用 Restarter
的实例进行重启。

在重启方法中还传入了 FileWatchingFailureHandler
并且使用了 fileSystemWatcherFactory

FileWatchingFailureHandler
实现了 FailureHandler
接口,该接口用于在重启的启动过程中,如果出错了,要采取什么策略去进行下去,该接口方法返回的结果只有两种, Outcome.ABORT
中止或 Outcome.RETRY
重试。

FileWatchingFailureHandler
中会通过 fileSystemWatcherFactory
创建一个新的文件监控,当类路径的内容发生变化时(不需要考虑是否需要重启,因为已经停止,并且没启动成功)就尝试重新启动。这种策略可以解决当配置或者代码出错无法启动时,可以修改BUG解决错误,然后 devtools 自动尝试启动。

FileWatchingFailureHandler
中的 FileSystemWatcher
和 3.2.3 中的不是同一个,并且在重启前另一个已经关闭,关闭的目的不是为了防止和这里存在两个监控出现冲突,而是为了防止第一次修改后,还没有重启时又发生了变化,由于重启需要时间,这就会导致重启还没完成就又重启了,这种情况下除了会产生错误外,还会因为短时间内频繁重启导致重启时间过长。

在重启时,会先关闭所有的 Spring Context,此时也会触发 ClassPathFileSystemWatcher
中的 destroy
方法:

@Override
public void destroy() throws Exception {
    this.fileSystemWatcher.stop();
}

destroy
中也会关闭文件监控,所以无论如何都不会和这里的 FileSystemWatcher
产生冲突。

3.3 重启后会重新初始化 Spring

关闭再启动时,devtools 通过反射执行的我们自己的 XXApplication
类的 main
方法,因此 LocalDevToolsAutoConfiguration
也会重新初始化,类路径监控也会重新建立。我们现在只是了解了从文件监控、类路径监控以及监控配置启动和触发重启的过程。有很多关键的处理过程和 RestartClassLoader
以及 Restarter
有关,为了防止过长篇幅使得关注点太过分散,后续会分别介绍这两部分内容。

原文 

https://blog.csdn.net/isea533/article/details/80147082

本站部分文章源于互联网,本着传播知识、有益学习和研究的目的进行的转载,为网友免费提供。如有著作权人或出版方提出异议,本站将立即删除。如果您对文章转载有任何疑问请告之我们,以便我们及时纠正。

PS:推荐一个微信公众号: askHarries 或者qq群:474807195,里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化这些成为架构师必备的知识体系。还能领取免费的学习资源,目前受益良多

转载请注明原文出处:Harries Blog™ » Spring Developer Tools 源码分析:三、重启自动配置

赞 (0)
分享到:更多 ()

评论 0

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址