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:

Image

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 Provider<T> wouldn't need to go through the resolution process again when calling providerBean.get() more than once. Is there a cache mechanism that can be leveraged to minimize the steps involved in dependency resolution on subsequent get() calls?"

Comment From: jhoeller

I've attempted to restore good concurrent performance for the shortcut code path through caching each primary bean type next along with the primary bean names, avoiding a general singleton lookup for that purpose. This will make it into the upcoming 6.2.11 snapshot and hopefully resolve your immediate problem.

I'll create a separate issue for considering caching a resolved singleton bean in a Provider instance where applicable. This is not entirely trivial since providers are meant to call back into the core container for a fresh lookup, picking up the current scoped instance or even a changed singleton definition - even if the most common usage is probably for lazy singleton lookup indeed.

Comment From: github-actions[bot]

Fixed via c248f94e5a6fb7cfc085ee9a9e39ad9293be9ae0