mirror of
https://github.com/spring-projects/spring-boot.git
synced 2026-10-06 17:29:19 +00:00
Merge pull request #46289 from move-hoon
* pr/46289: Polish "Optimize DevTools resource lookup performance" Optimize DevTools resource lookup performance Closes gh-46289
This commit is contained in:
+17
-22
@@ -33,7 +33,6 @@ import org.springframework.boot.devtools.restart.classloader.ClassLoaderFile;
|
||||
import org.springframework.boot.devtools.restart.classloader.ClassLoaderFile.Kind;
|
||||
import org.springframework.boot.devtools.restart.classloader.ClassLoaderFileURLStreamHandler;
|
||||
import org.springframework.boot.devtools.restart.classloader.ClassLoaderFiles;
|
||||
import org.springframework.boot.devtools.restart.classloader.ClassLoaderFiles.SourceDirectory;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.support.AbstractApplicationContext;
|
||||
import org.springframework.core.io.AbstractResource;
|
||||
@@ -125,15 +124,13 @@ final class ClassLoaderFilesResourcePatternResolver implements ResourcePatternRe
|
||||
private List<Resource> getAdditionalResources(String locationPattern) throws MalformedURLException {
|
||||
List<Resource> additionalResources = new ArrayList<>();
|
||||
String trimmedLocationPattern = trimLocationPattern(locationPattern);
|
||||
for (SourceDirectory sourceDirectory : this.classLoaderFiles.getSourceDirectories()) {
|
||||
for (Entry<String, ClassLoaderFile> entry : sourceDirectory.getFilesEntrySet()) {
|
||||
String name = entry.getKey();
|
||||
ClassLoaderFile file = entry.getValue();
|
||||
if (file.getKind() != Kind.DELETED && this.antPathMatcher.match(trimmedLocationPattern, name)) {
|
||||
URL url = new URL("reloaded", null, -1, "/" + name, new ClassLoaderFileURLStreamHandler(file));
|
||||
UrlResource resource = new UrlResource(url);
|
||||
additionalResources.add(resource);
|
||||
}
|
||||
for (Entry<String, ClassLoaderFile> entry : this.classLoaderFiles.getFileEntries()) {
|
||||
String name = entry.getKey();
|
||||
ClassLoaderFile file = entry.getValue();
|
||||
if (file.getKind() != Kind.DELETED && this.antPathMatcher.match(trimmedLocationPattern, name)) {
|
||||
URL url = new URL("reloaded", null, -1, "/" + name, new ClassLoaderFileURLStreamHandler(file));
|
||||
UrlResource resource = new UrlResource(url);
|
||||
additionalResources.add(resource);
|
||||
}
|
||||
}
|
||||
return additionalResources;
|
||||
@@ -149,20 +146,18 @@ final class ClassLoaderFilesResourcePatternResolver implements ResourcePatternRe
|
||||
}
|
||||
|
||||
private boolean isDeleted(Resource resource) {
|
||||
for (SourceDirectory sourceDirectory : this.classLoaderFiles.getSourceDirectories()) {
|
||||
for (Entry<String, ClassLoaderFile> entry : sourceDirectory.getFilesEntrySet()) {
|
||||
try {
|
||||
String name = entry.getKey();
|
||||
ClassLoaderFile file = entry.getValue();
|
||||
if (file.getKind() == Kind.DELETED && resource.exists()
|
||||
&& resource.getURI().toString().endsWith(name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new IllegalStateException("Failed to retrieve URI from '" + resource + "'", ex);
|
||||
for (Entry<String, ClassLoaderFile> entry : this.classLoaderFiles.getFileEntries()) {
|
||||
try {
|
||||
String name = entry.getKey();
|
||||
ClassLoaderFile file = entry.getValue();
|
||||
if (file.getKind() == Kind.DELETED && resource.exists()
|
||||
&& resource.getURI().toString().endsWith(name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new IllegalStateException("Failed to retrieve URI from '" + resource + "'", ex);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
+23
-12
@@ -42,15 +42,23 @@ import org.springframework.util.Assert;
|
||||
*/
|
||||
public class ClassLoaderFiles implements ClassLoaderFileRepository, Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1;
|
||||
|
||||
private final Map<String, SourceDirectory> sourceDirectories;
|
||||
|
||||
/**
|
||||
* A flattened map of all files from all source directories for fast, O(1) lookups.
|
||||
* The key is the file's relative path, and the value is the ClassLoaderFile.
|
||||
*/
|
||||
private final Map<String, ClassLoaderFile> filesByName;
|
||||
|
||||
/**
|
||||
* Create a new {@link ClassLoaderFiles} instance.
|
||||
*/
|
||||
public ClassLoaderFiles() {
|
||||
this.sourceDirectories = new LinkedHashMap<>();
|
||||
this.filesByName = new LinkedHashMap<>();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -60,6 +68,7 @@ public class ClassLoaderFiles implements ClassLoaderFileRepository, Serializable
|
||||
public ClassLoaderFiles(ClassLoaderFiles classLoaderFiles) {
|
||||
Assert.notNull(classLoaderFiles, "'classLoaderFiles' must not be null");
|
||||
this.sourceDirectories = new LinkedHashMap<>(classLoaderFiles.sourceDirectories);
|
||||
this.filesByName = new LinkedHashMap<>(classLoaderFiles.filesByName);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -97,12 +106,14 @@ public class ClassLoaderFiles implements ClassLoaderFileRepository, Serializable
|
||||
Assert.notNull(file, "'file' must not be null");
|
||||
removeAll(name);
|
||||
getOrCreateSourceDirectory(sourceDirectory).add(name, file);
|
||||
this.filesByName.put(name, file);
|
||||
}
|
||||
|
||||
private void removeAll(String name) {
|
||||
for (SourceDirectory sourceDirectory : this.sourceDirectories.values()) {
|
||||
sourceDirectory.remove(name);
|
||||
}
|
||||
this.filesByName.remove(name);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -128,22 +139,22 @@ public class ClassLoaderFiles implements ClassLoaderFileRepository, Serializable
|
||||
* @return the size of the collection
|
||||
*/
|
||||
public int size() {
|
||||
int size = 0;
|
||||
for (SourceDirectory sourceDirectory : this.sourceDirectories.values()) {
|
||||
size += sourceDirectory.getFiles().size();
|
||||
}
|
||||
return size;
|
||||
return this.filesByName.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable ClassLoaderFile getFile(String name) {
|
||||
for (SourceDirectory sourceDirectory : this.sourceDirectories.values()) {
|
||||
ClassLoaderFile file = sourceDirectory.get(name);
|
||||
if (file != null) {
|
||||
return file;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
return this.filesByName.get(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a set of all file entries across all source directories for efficient
|
||||
* iteration.
|
||||
* @return a set of all file entries
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public Set<Entry<String, ClassLoaderFile>> getFileEntries() {
|
||||
return Collections.unmodifiableSet(this.filesByName.entrySet());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user