首页 > 编程 > Java > 正文

SpringBoot的reload加载器的方法

2019-11-26 10:10:29
字体:
来源:转载
供稿:网友

背景

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

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

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表