Affects: 5.1.4

I was attempting to fix https://github.com/spring-projects/spring-amqp/issues/885 to avoid eager initialization of a lazy factory bean as reported in the linked Stack Overflow question.

After fixing it, I found the FB is still instantiated, but by the EventListenerMethodProcessor instead...

https://github.com/spring-projects/spring-framework/blob/155ef5fd778579c9bae3469244a3aee64f079ac5/spring-context/src/main/java/org/springframework/context/event/EventListenerMethodProcessor.java#L100-L103

Comment From: snicoll

There are a number of candidates that would do that sort of things. @EventListener and @JmsListener come to mind. If there is a more general approach we could use to do that stuff, It should be applied most probably to other projects as well.

ping @jhoeller

Comment From: garyrussell

The simple fix would be beanFactory.getBeanNamesForType(Object.class, false, false); - but that would mean a behavior change because any lazy beans with @EventListener won't get events.

Comment From: qsLI

Same here! Our application loaded 20, 000 extra classes because of getDeclaredMethod of lazy beans. We saved about 40 seconds by skipping lazy bean here.

Comment From: qsLI

@sbrannen @snicoll Please pay attention to this issue. Thanks in advance.

Comment From: jhoeller

Reviewing this from a 6.2 perspective and experimenting with the effects in a common scenarios, I am not convinced that a change in EventListenerMethodProcessor would make a real difference here. Every getBean(Class) performs the same level of eager initialization for type determination, and there is hardly any application without such a call involved these days.

To reliably avoid eager initialization of a FactoryBean for type determination purposes, I recommend setting FactoryBean.OBJECT_TYPE_ATTRIBUTE via BeanDefinition.setAttribute so that the container can infer the produced type upfront without having to call FactoryBean.getObjectType(). That attribute option is available since 5.2, shortly after the origin of this issue. Aside from that, type determination only creates the FactoryBean instance for a getObjectType() call, not calling getObject() yet; this can be leveraged for certain FactoryBean implementation styles that lazily create the exposed object from an eagerly created FactoryBean instance.

As for expensive reflection steps, we cache declared methods etc, so this should be reasonably efficient for beans that have been introspected before. However, for a lazy-init bean class not seen before at all, we would initiate reflection there indeed. How this could arrive at 20000 extra classes, I have no idea... If there are so many lazy beans with so many different classes involved, I would seriously slice the application's configuration to what is actually needed, instead of apparently defining lots of unnecessary beans which will never get used in the current run. Lazy beans are meant to be used selectively for certain use cases, mostly around rarely used application functionality that is only to be initialized when actually requested. Even there, warming up such lazy classes upfront can be seen as part of the container's startup measures; it's instantiation that is lazy, not introspection of the class.