Hi,
I am currently trying to improve startup time of a medium sized Spring-Boot app that currently takes around 20 seconds to start. While profiling I noticed that the top hotspot is AbstractAutowireCapableBeanFactory#predictBeanType as shown in the screenshot below:
Additionally you can seeIterator.hasNext()/next() which are also in the top of the list. I found out that a reasonable time is spent iterating over BeanPostProcessors (23 in my case) for every bean, although most of the post-processors are not a SmartInstantiationAwareBeanPostProcessor at all (only 3 in my case), which are the only post-processors of interest for predicting bean types. Even worse, almost all standard smart post-processors are anyway returning null.
The idea of this PR is to hold an additional list of smart post-processors that can be used to minimize the iteration overhead in cases where only SmartInstantiationAwareBeanPostProcessor instances are of interest. Applying this patch shows the following results in the profiling and saves around 1-2 seconds for me:
Let me know what you think. Cheers, Christoph
Comment From: dreis2211
If #24756 is merged, this PR needs to adapt as well. Or vice versa, obviously.
Comment From: dreis2211
Anyone willing to review?
Comment From: jhoeller
I suppose you are trying to optimize singleton creation performance there, that is, many separate beans of distinct types? I was wondering before whether to cache post-processor applicability to individual beans but that would only improve repeated creation attempts for non-singleton beans...
Comment From: dreis2211
It's indeed many separate @Services or @Components we're talking about, each of them autowiring a couple of other beans (let's say 5 on average - but that is only based on a gut-feeling). And before you ask: I unfortunately can't provide the application at hand. :/
Comment From: dreis2211
Any chance this might be included in the next release, @jhoeller ? (5.3.0 or even better: 5.2.7)
Comment From: dreis2211
I think that could also help on https://github.com/spring-projects/spring-framework/issues/22060
Comment From: jhoeller
I've implemented a different approach: an internal cache for pre-filtered post-processors, used within the AbstractBeanFactory hierarchy with no impact on outside packages. This is as fine-grained as possible now, differentiating not only SmartInstantiationAware but regular InstantiationAware, DestructionAware and MergedBeanDefinitionPostProcessor as well, also replacing the existing hasInstantiationAware and hasDestructionAware fields with the new single volatile post-processor cache... which is getting reset in addBeanPostProcessor.
To be committed ASAP, I'll simply repurpose this PR for it (I hope you're ok with that approach).
Comment From: dreis2211
Obviously, I appreciate a contribution as much as anyone - but I care more about the problem being fixed, so feel free to go on. I'll take a look once you committed it, because I can't really tell from your description if that actually solves the problem (of simply too many iterations on irrelevant post processors)