Version: Spring 6.2.9
We've observed a performance regression in our application related to Singleton beans that use jakarta.inject.Provider<T>
in their constructors, where one of the methods subsequently invokes the provided bean.
Sample:
public class MyService {
private final Provider<AnotherService> anotherServiceProvider;
public MyService(Provider<AnotherService> anotherServiceProvider, ....) {
this.anotherServiceProvider = anotherServiceProvider;
}
public void doSomething() {
AnotherService anotherService = anotherServiceProvider.get();
anotherService.performAction();
}
}
Method Profiling shows:
No such regression is seen in the application when running with Spring 6.1
The issue seen could be due to Step 3 optimization introduced as part of this change. Didnt find this in Spring 6.1 version
The code calls the hasPrimaryConflict that then calls the isTypeMatch
that ends up calling getSingleton(...)
.
We have over 50K beans in the ApplicationContext.
I suspect that the call to getSingleton()
within the hasPrimaryConflict
method—executed while iterating over all primaryBeanNames—is contending for the global lock, which may be held by other threads creating Spring beans, thereby slowing down bean resolution via Provider<T>
.
I believe reversing the if condition logic here could help short-circuit the isTypeMatch
check (might not help with this case though).
if (!candidate.equals(beanName) && isTypeMatch(candidate, dependencyType)) {
return true;
}
On a related note, I was under the impression that singleton beans accessed via ProviderproviderBean.get()
. Is there a cache mechanism that can be leveraged to minimize the steps involved in dependency resolution?"