直接调appclassLoader加载,仅仅修改类的话,已被加载的类不会重新加载所以需要自定义类加载器,要想重新加载需要重构类加载器。
1.加载过程启动类SpringApplication
public SpringApplication(ResourceLoader resourceLoader, Class>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new linkedHashSet<>(Arrays.asList(primarySources));
this.webApplicationType = WebApplicationType.deduceFromClasspath();
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
//获取所有的监听器
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
//加载SpringApplicationRunListeners
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
//获取监听器
SpringApplicationRunListeners listeners = getRunListeners(args);
//触发监听
listeners.starting();
....
}
EventPublishingRunListener监听器发布事件
public void starting() {
this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
}
//this.defaultRetriever.applicationListeners变量
//EventPublishingRunListener 构造器
public EventPublishingRunListener(SpringApplication application, String[] args) {
this.application = application;
this.args = args;
this.initialMulticaster = new SimpleApplicationEventMulticaster();
//从SpringApplication的全局变量listeners中获取监听器
for (ApplicationListener> listener : application.getListeners()) {
this.initialMulticaster.addApplicationListener(listener);
}
}
//监听器存入this.defaultRetriever.applicationListeners
public void addApplicationListener(ApplicationListener> listener) {
synchronized (this.retrievalMutex) {
// Explicitly remove target for a proxy, if registered already,
// in order to avoid double invocations of the same listener.
Object singletonTarget = AopProxyUtils.getSingletonTarget(listener);
if (singletonTarget instanceof ApplicationListener) {
this.defaultRetriever.applicationListeners.remove(singletonTarget);
}
this.defaultRetriever.applicationListeners.add(listener);
this.retrieverCache.clear();
}
}
SimpleApplicationEventMulticaster多播器
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
Executor executor = getTaskExecutor();
for (ApplicationListener> listener : getApplicationListeners(event, type)) {//获取监听器遍历
//调用监听
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
}
else {
invokeListener(listener, event);
}
}
}
//监听调用
protected void invokeListener(ApplicationListener> listener, ApplicationEvent event) {
ErrorHandler errorHandler = getErrorHandler();
if (errorHandler != null) {
try {
doInvokeListener(listener, event);
}
catch (Throwable err) {
errorHandler.handleError(err);
}
}
else {
doInvokeListener(listener, event);
}
}
调用监听器RestartApplicationListener
private void onApplicationStartingEvent(ApplicationStartingEvent event) {
String enabled = System.getProperty(ENABLED_PROPERTY);//spring.devtools.restart.enabled
if (enabled == null || Boolean.parseBoolean(enabled)) {//通过该变量控制是否热部署
String[] args = event.getArgs();
DefaultRestartInitializer initializer = new DefaultRestartInitializer();
boolean restartonInitialize = !AgentReloader.isActive();
if (!restartOnInitialize) {
logger.info("Restart disabled due to an agent-based reloader being active");
}
Restarter.initialize(args, false, initializer, restartOnInitialize);
}
else {
logger.info(LogMessage.format("Restart disabled due to System property '%s' being set to false",
ENABLED_PROPERTY));
Restarter.disable();
}
}
Restarter重启类
public static void initialize(String[] args, boolean forceReferenceCleanup, RestartInitializer initializer,
boolean restartOnInitialize) {
Restarter localInstance = null;
synchronized (INSTANCE_MONITOR) {
if (instance == null) {
localInstance = new Restarter(Thread.currentThread(), args, forceReferenceCleanup, initializer);
instance = localInstance;
}
}
if (localInstance != null) {
localInstance.initialize(restartOnInitialize);
}
}
protected void initialize(boolean restartOnInitialize) {
preInitializeLeakyClasses();
if (this.initialUrls != null) {
this.urls.addAll(Arrays.asList(this.initialUrls));
if (restartOnInitialize) {
this.logger.debug("Immediately restarting application");
immediateRestart();
}
}
}
private void immediateRestart() {
try {
getLeakSafeThread().callAndWait(() -> {
start(FailureHandler.NONE);//异步线程
cleanupCaches();
return null;
});
}
catch (Exception ex) {
this.logger.warn("Unable to initialize restarter", ex);
}
SilentExitExceptionHandler.exitCurrentThread();//主线程抛异常退出
}
protected void start(FailureHandler failureHandler) throws Exception {
do {
Throwable error = doStart();
if (error == null) {
return;
}
if (failureHandler.handle(error) == Outcome.ABORT) {
return;
}
}
while (true);
}
private Throwable doStart() throws Exception {
Assert.notNull(this.mainClassName, "Unable to find the main class to restart");
URL[] urls = this.urls.toArray(new URL[0]);
ClassLoaderFiles updatedFiles = new ClassLoaderFiles(this.classLoaderFiles);
ClassLoader classLoader = new RestartClassLoader(this.applicationClassLoader, urls, updatedFiles, this.logger);//新建类加载器new RestartClassLoader
if (this.logger.isDebugEnabled()) {
this.logger.debug("Starting application " + this.mainClassName + " with URLs " + Arrays.asList(urls));
}
return relaunch(classLoader);//重新运行程序relaunch,传入RestartClassLoader
}
protected Throwable relaunch(ClassLoader classLoader) throws Exception {
RestartLauncher launcher = new RestartLauncher(classLoader, this.mainClassName, this.args,
this.exceptionHandler);
launcher.start();
launcher.join();
return launcher.getError();
}
RestartLauncher
RestartLauncher(ClassLoader classLoader, String mainClassName, String[] args,
UncaughtExceptionHandler exceptionHandler) {
this.mainClassName = mainClassName;
this.args = args;
setName("restartedMain");
setUncaughtExceptionHandler(exceptionHandler);
setDaemon(false);
setContextClassLoader(classLoader);//设置类加载器
}
//重新运行主程序 SpringApplication.run
@Override
public void run() {
try {
Class> mainClass = Class.forName(this.mainClassName, false, getContextClassLoader());
Method mainMethod = mainClass.getDeclaredMethod("main", String[].class);
mainMethod.invoke(null, new Object[] { this.args });
}
catch (Throwable ex) {
this.error = ex;
getUncaughtExceptionHandler().uncaughtException(this, ex);
}
}
疑问:再次调用SpringApplication.run后,又得调用RestartApplicationListener的onApplicationStartingEvent,不是造成死循环了吗?
答:其实第二次调用会跳出onApplicationStartingEvent的后续方法,执行到RestartApplicationListener的onApplicationStartingEvent时候
不会再走到Restarter.initialize方法去,故不会造成循环,具体跟源码看。
文件监听实现热部署文件监听自动配置类LocalDevToolsAutoConfiguration
spring.factories文件中
//重启触发策略ClassPathRestartStrategy
@Bean
@ConditionalOnMissingBean
ClassPathFileSystemWatcher classPathFileSystemWatcher(FileSystemWatcherFactory fileSystemWatcherFactory,
ClassPathRestartStrategy classPathRestartStrategy) {
URL[] urls = Restarter.getInstance().getInitialUrls();//监听的路径url
//真正监听的实体类FileSystemWatcher
ClassPathFileSystemWatcher watcher = new ClassPathFileSystemWatcher(fileSystemWatcherFactory,
classPathRestartStrategy, urls);
watcher.setStopWatcheronRestart(true);
return watcher;
}
//监听ClassPathChangedEvent事件,触发Restarter重启应用
@Bean
ApplicationListener restartingClassPathChangedEventListener(
FileSystemWatcherFactory fileSystemWatcherFactory) {
return (event) -> {
if (event.isRestartRequired()) {
//调用Restarter
Restarter.getInstance().restart(new FileWatchingFailureHandler(fileSystemWatcherFactory));
}
};
}
ClassPathFileSystemWatcher
//实现了InitializingBean
@Override
public void afterPropertiesSet() throws Exception {
if (this.restartStrategy != null) {
FileSystemWatcher watcherToStop = null;
if (this.stopWatcherOnRestart) {
watcherToStop = this.fileSystemWatcher;
}
//加入ClassPathFileChangeListener对象
this.fileSystemWatcher.addListener(
new ClassPathFileChangeListener(this.applicationContext, this.restartStrategy, watcherToStop));
}
this.fileSystemWatcher.start();
}
FileSystemWatcher
public void run() {
int remainingScans = this.remainingScans.get();
while (remainingScans > 0 || remainingScans == -1) {
try {
if (remainingScans > 0) {
this.remainingScans.decrementAndGet();
}
scan();//扫描对比文件快照和文件当前信息,查看是否有变化,有变化则触发监听
}
catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
remainingScans = this.remainingScans.get();
}
}
private void scan() throws InterruptedException {
Thread.sleep(this.pollInterval - this.quietPeriod);
Map previous;
Map current = this.directories;
do {
previous = current;
current = getCurrentSnapshots();//获取文件当前信息
Thread.sleep(this.quietPeriod);//休止期,默认400毫秒
}
while (isDifferent(previous, current));//对比文件,有差异则退出循环
if (isDifferent(this.directories, current)) {//休止期内,如果文件再改回去,相当于文件无变化
updateSnapshots(current.values());
}
}
private Map getCurrentSnapshots() {
Map snapshots = new linkedHashMap<>();
for (File directory : this.directories.keySet()) {
//获取文件当前信息封装到DirectorySnapshot
snapshots.put(directory, new DirectorySnapshot(directory));
}
return snapshots;
}
private void updateSnapshots(Collection snapshots) {
Map updated = new linkedHashMap<>();
Set changeSet = new linkedHashSet<>();
for (DirectorySnapshot snapshot : snapshots) {
DirectorySnapshot previous = this.directories.get(snapshot.getDirectory());
updated.put(snapshot.getDirectory(), snapshot);
ChangedFiles changedFiles = previous.getChangedFiles(snapshot, this.triggerFilter);
if (!changedFiles.getFiles().isEmpty()) {
changeSet.add(changedFiles);
}
}
if (!changeSet.isEmpty()) {
fireListeners(Collections.unmodifiableSet(changeSet));//发布监听事件
}
this.directories = updated;
}
//发布监听事件 ClassPathFileChangeListener
private void fireListeners(Set changeSet) {
for (FileChangeListener listener : this.listeners) {
listener.onChange(changeSet);
}
}
DirectorySnapshot判断文件是否发生变化的封装类
DirectorySnapshot(File directory) {
Assert.notNull(directory, "Directory must not be null");
Assert.isTrue(!directory.isFile(), () -> "Directory '" + directory + "' must not be a file");
this.directory = directory;
this.time = new Date();
Set files = new linkedHashSet<>();
collectFiles(directory, files);//收集文件快照
this.files = Collections.unmodifiableSet(files);//存储file文件,该快照集合不可修改
}
private void collectFiles(File source, Set result) {
File[] children = source.listFiles();
if (children != null) {
for (File child : children) {
if (child.isDirectory() && !DOTS.contains(child.getName())) {
collectFiles(child, result);//递归处理
}
else if (child.isFile()) {
result.add(new FileSnapshot(child));//存储文件快照的对象
}
}
}
}
//存储文件长度、最后修改时间 该类已重写equals方法
FileSnapshot(File file) {
Assert.notNull(file, "File must not be null");
Assert.isTrue(file.isFile() || !file.exists(), "File must not be a directory");
this.file = file;
this.exists = file.exists();
this.length = file.length();
this.lastModified = file.lastModified();
}
ClassPathFileChangeListener,实现热部署
@Override public void onChange(Set热部署原理图changeSet) { boolean restart = isRestartRequired(changeSet); publishEvent(new ClassPathChangedEvent(this, changeSet, restart)); } private void publishEvent(ClassPathChangedEvent event) { this.eventPublisher.publishEvent(event);//发布事件 ClassPathChangedEvent if (event.isRestartRequired() && this.fileSystemWatcherToStop != null) { this.fileSystemWatcherToStop.stop(); } }
https://www.processon.com/view/link/621cdfb8f346fb5010961fc2



