SpringBoot的reload加載器的方法
背景
springboot越來(lái)越多的被大家所使用SpringBoot DevTool實(shí)現(xiàn)熱部署
出現(xiàn)了相同類(lèi)castException
分析
首先確定出現(xiàn)相同類(lèi)的castException比如是由于classloader不同造成的。
一個(gè)class是否相同取決于兩個(gè)因素
- classloader相同
- class文件相同
即不同classloader解釋出來(lái)的class是不同的class
我們?cè)趯W(xué)習(xí)jdbc的時(shí)候常見(jiàn)的使用
/**
* 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也無(wú)法互相轉(zhuǎn)換
這樣我們把目標(biāo)放在devtools上。
我們?cè)趕pringboot中引入了如下依賴(lài)
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <optional>true</optional> </dependency>
那么如何排除devtool的依賴(lài)呢?
在application.properties中增加
spring.devtools.restart.enabled=false
發(fā)現(xiàn)啟動(dòng)時(shí)仍然可以看出使用的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
這邊線(xiàn)程名為restartedMain 為啥設(shè)置spring.devtools.restart.enabled 無(wú)效呢?
代碼
在對(duì)應(yīng)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();
}
}
很明顯其實(shí)restarter的開(kāi)啟是從系統(tǒng)變量中讀取 而并非從spring的環(huán)境中讀取 正如注釋所說(shuō) 其實(shí)此刻使用spring的property還太早
因此可以使用系統(tǒng)變量
因此我們可以使用jvm參數(shù)

-Dspring.devtools.restart.enabled=false
果然此時(shí)一切就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;
}
從代碼中看到似乎是用來(lái)配置是否監(jiān)聽(tīng)能否自動(dòng)重啟
/**
* 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;
}
}
}
整個(gè)根據(jù)該配置來(lái)返回是否注冊(cè)對(duì)應(yīng)的watchService
當(dāng)然我們也可以移除該jar
需要注意的是 當(dāng)將這一段代碼注釋時(shí) 需要重新
mvn clean
否則有可能無(wú)法自動(dòng)排除該jar
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Java中浮點(diǎn)數(shù)精度問(wèn)題的解決方法
這篇文章給大家介紹了Java中浮點(diǎn)數(shù)精度問(wèn)題的解決方法,本文給大家介紹的非常詳細(xì),有問(wèn)題描述有原因分析,非常不錯(cuò),具有參考借鑒價(jià)值,感興趣的朋友一起看看吧2016-10-10
Java多線(xiàn)程中關(guān)于join方法的使用實(shí)例解析
本文通過(guò)實(shí)例代碼給大家實(shí)例介紹了Java多線(xiàn)程中關(guān)于join方法的使用,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友參考下2017-01-01
Spring中如何動(dòng)態(tài)注入Bean實(shí)例教程
這篇文章主要給大家介紹了關(guān)于Spring中如何動(dòng)態(tài)注入Bean的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。2017-12-12
Sleuth+logback 設(shè)置traceid 及自定義信息方式
這篇文章主要介紹了Sleuth+logback 設(shè)置traceid 及自定義信息方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07
Spring Boot 集成 Kafkad的實(shí)現(xiàn)示例
這篇文章主要介紹了Spring Boot 集成 Kafkad的示例,幫助大家更好的理解和學(xué)習(xí)使用Spring Boot框架,感興趣的朋友可以了解下2021-04-04
java背包問(wèn)題動(dòng)態(tài)規(guī)劃算法分析
這篇文章主要介紹了java背包問(wèn)題動(dòng)態(tài)規(guī)劃算法分析,想了解算法的同學(xué)一定要看一下2021-04-04
詳解如何為SpringBoot Web應(yīng)用的日志方便追蹤
在Web應(yīng)用程序領(lǐng)域,有效的請(qǐng)求監(jiān)控和可追溯性對(duì)于維護(hù)系統(tǒng)完整性和診斷問(wèn)題至關(guān)重要,SpringBoot是一種用于構(gòu)建Java應(yīng)用程序的流行框架,在本文中,我們探討了在SpringBoot中向日志添加唯一ID的重要性,需要的朋友可以參考下2023-11-11

