Skip to content

Optimize resource lookup in DevTools restart #46289

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

hoonyworld
Copy link

Optimize resource lookup in DevTools restart

This pull request significantly improves the performance of resource lookups within the DevTools restart mechanism, particularly benefiting projects with a large number of files and source directories.

Motivation and Problem

The existing ClassLoaderFilesResourcePatternResolver and its underlying ClassLoaderFiles implementation suffer from performance degradation in large-scale projects. Key methods such as getFile(), size(), isDeleted(), and getAdditionalResources() rely on nested loops that iterate through all source directories and their respective files. This results in a time complexity of O(n*m) for many critical operations, where 'n' is the number of source directories and 'm' is the number of files. As a project grows, these repeated iterations can introduce noticeable delays during application restarts.

Solution

This PR addresses the performance bottleneck by refactoring ClassLoaderFiles to use a pre-computed, flattened map for direct lookups, and updating ClassLoaderFilesResourcePatternResolver to leverage this new, efficient structure.

1. ClassLoaderFiles Refactoring:

  • Introduced a Flattened Map:
    A new Map<String, ClassLoaderFile> filesByName field has been added. This map is populated once at construction time and serves as a unified, central cache for all files across all source directories.
  • O(1) Complexity for Core Methods:
    • getFile(name) now performs a direct get() on the filesByName map, reducing its complexity from O(n) to O(1).
    • size() now directly returns filesByName.size(), reducing its complexity from O(n) to O(1).
  • Data Consistency:
    The addFile() and removeAll() methods have been updated to ensure that both the original sourceDirectories map and the new filesByName map are kept in sync, guaranteeing data integrity.
  • New Efficient Iterator:
    A new getFileEntries() method provides a way to iterate over all files in a single loop, which is used by the resolver.

2. ClassLoaderFilesResourcePatternResolver Optimization:

  • Optimized isDeleted():
    This method has been refactored to eliminate the nested loop structure (from O(n*m) to O(m)). It now iterates over the single, unified collection provided by classLoaderFiles.getFileEntries(), significantly reducing the complexity of the operation while preserving the original exception handling behavior.
  • Optimized getAdditionalResources():
    Similarly, this method now iterates over the single, unified collection provided by classLoaderFiles.getFileEntries(), eliminating the outer loop and improving readability and performance.

Benefits

Significant Performance Improvement:
Reduces the time complexity of critical file lookup operations. Direct lookups like getFile are improved from O(n) to O(1), while iterative searches like isDeleted are improved from O(n*m) to O(m), leading to faster application restarts in DevTools.

Enhanced Code Quality:
Eliminates nested loops, which simplifies the code, improves readability, and makes the logic easier to maintain.

Minimal Memory Overhead:
The optimization introduces a map of references, not data duplicates. The trade-off of a negligible increase in memory usage for a substantial performance gain is highly favorable.

This change maintains full backward compatibility with the existing API while providing a much-needed performance boost for developers working on large applications.

The resource resolver in DevTools can cause performance degradation
during application restarts in large projects. Key methods like
isDeleted() and getAdditionalResources() rely on nested loops, leading to O(n*m) complexity.

This commit refactors ClassLoaderFiles to use a pre-computed, flattened map. This provides O(1) complexity for direct lookups and allows for efficient single-loop iteration.

The ClassLoaderFilesResourcePatternResolver is updated to leverage this new, efficient structure:

- getFile() and size() are improved from O(n) to O(1).
- isDeleted() and getAdditionalResources() are improved from O(n*m) to O(m) by eliminating nested loops.
- Data consistency is maintained across all operations.

This optimization significantly improves restart performance with a minimal memory footprint, while preserving the existing API and exception handling behavior.
@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Jul 4, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: waiting-for-triage An issue we've not yet triaged
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants