SpringBoot的reload加载器的方法

 更新时间:2018年03月22日 14:08:13   作者:Mr_Qi  
本篇文章主要介绍了SpringBoot的reload加载器的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

背景

springboot越来越多的被大家所使用SpringBoot DevTool实现热部署

出现了相同类castException

分析

首先确定出现相同类的castException比如是由于classloader不同造成的。

一个class是否相同取决于两个因素

  1. classloader相同
  2. class文件相同

即不同classloader解释出来的class是不同的class

我们在学习jdbc的时候常见的使用

/**
 * Returns the {@code Class} object associated with the class or
 * interface with the given string name. Invoking this method is
 * equivalent to:
 *
 * <blockquote>
 * {@code Class.forName(className, true, currentLoader)}
 * </blockquote>
 *
 * where {@code currentLoader} denotes the defining class loader of
 * the current class.
 *
 * <p> For example, the following code fragment returns the
 * runtime {@code Class} descriptor for the class named
 * {@code java.lang.Thread}:
 *
 * <blockquote>
 *  {@code Class t = Class.forName("java.lang.Thread")}
 * </blockquote>
 * <p>
 * A call to {@code forName("X")} causes the class named
 * {@code X} to be initialized.
 *
 * @param   className  the fully qualified name of the desired class.
 * @return   the {@code Class} object for the class with the
 *       specified name.
 * @exception LinkageError if the linkage fails
 * @exception ExceptionInInitializerError if the initialization provoked
 *      by this method fails
 * @exception ClassNotFoundException if the class cannot be located
 */
public static Class<?> forName(String className)
      throws ClassNotFoundException {
  return forName0(className, true, ClassLoader.getCallerClassLoader());
}

从上面我们可以了解不同的classloader解释的相同class也无法互相转换

这样我们把目标放在devtools上。

我们在springboot中引入了如下依赖

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-devtools</artifactId>
  <optional>true</optional>
</dependency>

那么如何排除devtool的依赖呢?

在application.properties中增加

spring.devtools.restart.enabled=false

发现启动时仍然可以看出使用的restartedMain

2018-03-19 22:04:37.641  INFO 53428 --- [restartedMain] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@7443f7a3: startup date [Mon Mar 19 22:03:34 CST 2018]; root of context hierarchy
2018-03-19 22:04:37.654  INFO 53428 --- [restartedMain] s.w.s.m.m.a.RequestMappingHandlerAdapter : Detected ResponseBodyAdvice bean in org.springframework.boot.actuate.autoconfigure.EndpointWebMvcHypermediaManagementContextConfiguration$ActuatorEndpointLinksAdvice
2018-03-19 22:04:37.956  INFO 53428 --- [restartedMain] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/swagger-ui.html] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2018-03-19 22:04:37.956  INFO 53428 --- [restartedMain] o.s.w.s.handler.SimpleUrlHandlerMapping  

这边线程名为restartedMain 为啥设置spring.devtools.restart.enabled 无效呢?

代码

在对应devtools的包中使用了ApplicationListener

private void onApplicationStartingEvent(ApplicationStartingEvent event) {
  // It's too early to use the Spring environment but we should still allow
  // users to disable restart using a System property.
  String enabled = System.getProperty(ENABLED_PROPERTY);
  if (enabled == null || Boolean.parseBoolean(enabled)) {
   String[] args = event.getArgs();
   DefaultRestartInitializer initializer = new DefaultRestartInitializer();
   boolean restartOnInitialize = !AgentReloader.isActive();
   Restarter.initialize(args, false, initializer, restartOnInitialize);
  }
  else {
   Restarter.disable();
  }
}

很明显其实restarter的开启是从系统变量中读取 而并非从spring的环境中读取 正如注释所说 其实此刻使用spring的property还太早

因此可以使用系统变量

因此我们可以使用jvm参数

-Dspring.devtools.restart.enabled=false

果然此时一切就OK了

2018-03-19 22:18:12.928  INFO 66260 --- [main] com.f6car.base.Application               : The following profiles are active: dev
2018-03-19 22:18:13.131  INFO 66260 --- [main] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@2a4354cb: startup date [Mon Mar 19 22:18:13 CST 2018]; root of context hierarchy

那在Spring的配置文件中配置的目的是啥呢?

/**
 * Restart properties.
 */
public static class Restart {
 
  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";
 
  private static final long DEFAULT_RESTART_POLL_INTERVAL = 1000;
 
  private static final long DEFAULT_RESTART_QUIET_PERIOD = 400;
 
  /**
  * Enable automatic restart.
  */
  private boolean enabled = true;
 
  /**
  * Patterns that should be excluded from triggering a full restart.
  */
  private String exclude = DEFAULT_RESTART_EXCLUDES;
 
  /**
  * Additional patterns that should be excluded from triggering a full restart.
  */
  private String additionalExclude;
 
  /**
  * Amount of time (in milliseconds) to wait between polling for classpath changes.
  */
  private long pollInterval = DEFAULT_RESTART_POLL_INTERVAL;
 
  /**
  * Amount of quiet time (in milliseconds) required without any classpath changes
  * before a restart is triggered.
  */
  private long quietPeriod = DEFAULT_RESTART_QUIET_PERIOD;
 
  /**
  * Name of a specific file that when changed will trigger the restart check. If
  * not specified any classpath file change will trigger the restart.
  */
  private String triggerFile;
 
  /**
  * Additional paths to watch for changes.
  */
  private List<File> additionalPaths = new ArrayList<File>();
 
  public boolean isEnabled() {
   return this.enabled;
  }
 
  public void setEnabled(boolean enabled) {
   this.enabled = enabled;
  }

从代码中看到似乎是用来配置是否监听能否自动重启

/**
  * Local Restart Configuration.
  */
  @ConditionalOnProperty(prefix = "spring.devtools.restart", name = "enabled", matchIfMissing = true)
  static class RestartConfiguration {
 
   @Autowired
   private DevToolsProperties properties;
 
   @EventListener
   public void onClassPathChanged(ClassPathChangedEvent event) {
     if (event.isRestartRequired()) {
      Restarter.getInstance().restart(
         new FileWatchingFailureHandler(fileSystemWatcherFactory()));
     }
   }
 
   @Bean
   @ConditionalOnMissingBean
   public ClassPathFileSystemWatcher classPathFileSystemWatcher() {
     URL[] urls = Restarter.getInstance().getInitialUrls();
     ClassPathFileSystemWatcher watcher = new ClassPathFileSystemWatcher(
        fileSystemWatcherFactory(), classPathRestartStrategy(), urls);
     watcher.setStopWatcherOnRestart(true);
     return watcher;
   }
 
   @Bean
   @ConditionalOnMissingBean
   public ClassPathRestartStrategy classPathRestartStrategy() {
     return new PatternClassPathRestartStrategy(
        this.properties.getRestart().getAllExclude());
   }
 
   @Bean
   public HateoasObjenesisCacheDisabler hateoasObjenesisCacheDisabler() {
     return new HateoasObjenesisCacheDisabler();
   }
 
   @Bean
   public FileSystemWatcherFactory fileSystemWatcherFactory() {
     return new FileSystemWatcherFactory() {
 
      @Override
      public FileSystemWatcher getFileSystemWatcher() {
        return 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;
   }
 
  }
 
}

整个根据该配置来返回是否注册对应的watchService

当然我们也可以移除该jar

需要注意的是 当将这一段代码注释时 需要重新

mvn clean

否则有可能无法自动排除该jar

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • 浅谈升级Spring Cloud到Finchley后的一点坑

    浅谈升级Spring Cloud到Finchley后的一点坑

    这篇文章主要介绍了浅谈升级Spring Cloud到Finchley后的一点坑,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-10-10
  • 浅谈java异常处理之空指针异常

    浅谈java异常处理之空指针异常

    下面小编就为大家带来一篇浅谈java异常处理之空指针异常。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-10-10
  • Jenkins与SVN持续集成的示例代码

    Jenkins与SVN持续集成的示例代码

    这篇文章主要介绍了Jenkins与SVN持续集成的示例代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-03-03
  • Java之next()、nextLine()区别及问题解决

    Java之next()、nextLine()区别及问题解决

    这篇文章主要介绍了Java之next()、nextLine()区别及问题解决,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-08-08
  • Java使用字节流实现图片音频的复制

    Java使用字节流实现图片音频的复制

    今天带大家学习Java的相关知识,文章围绕着Java如何使用字节流实现图片音频的复制展开,文中有非常详细的介绍,需要的朋友可以参考下
    2021-06-06
  • Java中synchronized关键字修饰方法同步的用法详解

    Java中synchronized关键字修饰方法同步的用法详解

    synchronized可以用来同步静态和非静态方法,下面就具体来看一下Java中synchronized关键字修饰方法同步的用法详解:
    2016-06-06
  • Java Ribbon负载均衡详细讲解

    Java Ribbon负载均衡详细讲解

    Ribbon其实就是一个软负载均衡的客户端组件,他可以和其他所需请求的客户端结合使用,这篇文章主要介绍了Ribbon负载均衡服务调用案例代码,需要的朋友可以参考下
    2023-01-01
  • java使用WatchService监控文件夹示例

    java使用WatchService监控文件夹示例

    本篇文章主要介绍了java使用WatchService监控文件夹示例的资料,这里整理了详细的代码,有需要的小伙伴可以参考下。
    2017-02-02
  • httpclient connect连接请求方法源码解读

    httpclient connect连接请求方法源码解读

    这篇文章主要为大家介绍了httpclient connect连接请求方法解读,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-11-11
  • Java开发之普通web项目转为Maven项目的方法

    Java开发之普通web项目转为Maven项目的方法

    这篇文章主要给大家介绍了关于Java开发之普通web项目转为Maven项目的相关资料,文中通过图文将转换的方法步骤介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧。
    2017-12-12

最新评论