SpringBoot的reload加载器的方法

网友投稿 283 2023-02-11


SpringBoot的reload加载器的方法

背景

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

出现了相同类castException

分析

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

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

classloader相同

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:

*

*

* {@code Class.forName(className, true, currentLoader)}

*

*

* where {@code currentLoader} denotes the defining class loader of

* the current class.

*

*

For example, the following code fragment returns the

* runtime {@code Class} descriptor for the class named

* {@code java.lang.Thread}:

*

*

* {@code Class t = Class.forName("java.lang.Thread")}

*

*

* 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中引入了如下依赖

org.springframework.boot

spring-boot-devtools

true

那么如何排除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 ResponseBodyAdvicMyvShKCee 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_REhttp://START_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 additionalPaths = new ArrayList();

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 additionalPaths = restartProperties.getAdditionalPaths();

for (File path : additionalPaths) {

watcher.addSourceFolder(path.getAbsoluteFile());

}

return watcher;

}

}

}

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

当然我们也可以移除该jar

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

mvn clean

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


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:浅谈Webpack 持久化缓存实践
下一篇:基于JavaMail实现邮件发送
相关文章

 发表评论

暂时没有评论,来抢沙发吧~