Skip to content

Cache result of RepositoryInformationSupport.getQueryMethods() #3066

Closed
@dodgex

Description

@dodgex

Hey there,

I work on a project that has over 250 JPA Repositories (distributed over 3 databases / persistence unites). The startup time in development and also production takes a big hit due to this fact.

While searching for the reason for the long startup times, i came across the getQueryMethods() in RepositoryInformationSupport (in 2.7.x it was in DefaultRepositoryInformation) and that it scans the repository interface for all methods and builds a set of qualified query methods.

This method is called in a lot of places, and multiple times during startup. and some places get all methods, only to search for one single after this...

e.g
RepositoryInformationSupport.java#L126

@Override
public boolean isQueryMethod(Method method) {
	return getQueryMethods().stream().anyMatch(it -> it.equals(method));
}

or RepositoryInformation.java#L85-L91

default boolean hasCustomMethod() {
	return getQueryMethods().stream().anyMatch(this::isCustomMethod);
}

default boolean hasQueryMethods() {
	return getQueryMethods().iterator().hasNext();
}

While in most cases, this should not be a to big problem, for bigger projects this could have huge impact. and even smaller projects could start even faster.

For testing purposes, I created a copy of the org.springframework.data.repository.core.DefaultRepositoryInformation in my development environment and changed the getQueryMethods to keep the result of the first invocation and do not scan the class again.

For 3.2.3 my implementation looks like this:

private Set<Method> resultCache;

@Override
public Streamable<Method> getQueryMethods() {
	if (resultCache == null) {
		Streamable<Method> queryMethods = super.getQueryMethods();
		resultCache = Collections.unmodifiableSet(queryMethods.toSet());
	}
	return Streamable.of(resultCache);
}

With this small change, my project startup time shrinks from ~120 seconds to ~40-45 seconds using Spring Boot 3.2.3. That is an improvement of about 60%.

While I do not have a deeper knowledge of what impact/sideeffect it could have to only scan the repository interface once, I can say that i already had this change for Spring Boot 2 in place for now over a year (actually i stumbled over my custom DefaultRepositoryInformation while upgrading to SB3). For SB3 I havent done too much testing as of now, but at least there where no immediate issues.

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions