Auto configuration of MethodValidationPostProcessor in class org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration requires instance of Environment. Since the envirnonemt does not have @Lazy annotation it triggers autowire candidate resolution with lazyInit=true which in turn results in initialization of (at least) FactoryBeans.

Bean post processors should NOT use autowiring since the beans created just to check that they do not implement Environment are later not eligible for all other bean post processors - which is actually confirmed in log by lots of:

Bean 'xxx' of type [XXX] is not eligible for getting processed by all BeanPostProcessors

I have implemented custom ImportBeanDefinitionRegistrar. When I use it like this:

@SpringBootApplication
@Import(GenesysRegistrar.class)
public class IntegrationServer {
...
}

everything works fine. But if I create my own auto-configuration class:

@Configuration
@Import(GenesysRegistrar.class)
public class GenesysAutoConfiguration {
}

then bean definitions registered by GenesysRegistrar are created BEFORE MethodValidationPostProcessor during search for bean implementing Environment interface.

Comment From: wilkinsona

We have a number of auto-configuration classes of our own that @Import an ImportBeanDefinitionRegistrar and we haven't seen any problems with beans not being eligible for post-processing. I'd like to make sure that we fully understand the problem before making a change. @AlesD, to help us to do that, can you please provide a small sample that reproduces the behaviour you have described?

Comment From: AlesD

I have created small example to demosnstrate the issue. There is no way to upload files here so below is base64 encoded content od zip file. Save the text to file - example.txt and use commad line:

Anyway duritn creation of the example I have found the root cause of the problem. It is bacause I'm using factory bean that takes other bean as dependecy via constructor. The reason why I have chosen this aproach is beacause sometimes the bean definiton uses factory bean to create the bean instance and sometimes creates the bean instance directly. The class takes one parameter as constructor argument and some others as peorperties. Therefore I have created my factory bean in same way.

However during autoconfiguration the bean that is injected as constructor argument of the factory bean is eagerly initialized. Interesting thing is that this happens only if yusing auto configuration. If you remove META-INF/spring-factories from the example, the MyAutoConfiguration class will still be found and the beans "bean1" and "bean2" will still be instantiated - but this time correctly.

I have not found any information that using constructor arguments on factory beans is prohibited or bad practise. For "plain classes" I definitelly prefer constructor injection for required colaborators - especially if they can't be changed nad can be declared as final inside the class.

I can get around the issue by replacing constror argument on my factory with property. The registrar will have to handle "factory case" differently than "plain class" case, but that can be easily done.

I still belive, however, that the search for autowire candidates should be more careful about eagerly initializing every bean in inspects.

Comment From: snicoll

Thanks for the sample.

There is no way to upload files here

The comment area has a section that states you can attach files by dragging & dropping. I've moved that sample to a proper github repo, see https://github.com/snicoll-scratches/gh-20219. I've also edited your comment to remove the base64 content.

Comment From: snicoll

@jhoeller Andy and I looked at it and we don't think there is anything we can do in Spring Boot. Andy also feels this can be related to #13893. Thoughts?

Comment From: AlesD

OK - I changed the factory beans to use property injection instead of constructor injection.

What is strange is that the issue does not occur if you put @Import(MyRegistrar.class) on the main class or any other @Configuration class in application. It only happens during auto-configuration. I would expect that the bean definitions created by Registrar shall be created before MethodValidationPostProcessor is instantiated. But maybe tat is not true with JavaConfig.

Maybe it would be good to mention somewhere that constructor injection should be avoided for FactoryBean implementations. Maybe javadoc of PostProcessorRegistrationDelegate or its inner class BeanPostProcessorChecker that emits the "not eligible" info message?

Anyway thanks for feedback.

Comment From: wyhasany

I've also stumbled upon on this issue in my starter. I've used BeanFactory to help instantiate bean definition with help of autowiring constructor arguments. Because of logic in MethodValidationPostProcessor all arguments has been initiated too early causing:

Bean 'x' of type [y] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)

Workaround with property autowiring works smoothly. Thanks @AlesD !

@snicoll / @wilkinsona could you consider add some notes in documentation encouraging autowiring custom BeanFactories by property?

Comment From: snicoll

I have updated the sample to a supported version of the framework (5.3.x) and I can't reproduce the problem. Sorry we didn't get to it sooner but I can't reproduce. If you can, then please update the sample and we can reopen.

Comment From: AndreTeigler

Maybe I can provide a sample. Basic Spring Boot App including RabbitMQ support. Extending the RabbitConnectionFactoryBean and importing the SslProperties from Spring:

@Component public class SSLRabbitConnectionFactoryBean extends RabbitConnectionFactoryBean {

private final SslProperties SslProperties;

public SSLRabbitConnectionFactoryBean(SslProperties SslProperties){
    this.SslProperties = SslProperties;
}

}

Starting the application results in the error:

Bean 'spring.ssl-org.springframework.boot.autoconfigure.ssl.SslProperties' of type [org.springframework.boot.autoconfigure.ssl.SslProperties] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying). Is this bean getting eagerly injected into a currently created BeanPostProcessor [persistenceExceptionTranslationPostProcessor]? Check the corresponding BeanPostProcessor declaration and its dependencies.

If injection is done by Autowire the warning disappears.

demo.zip