Hi,
The suspected issue described below is related to the version 2.2.0.M1 of Spring Boot.
It appears that the management endpoints are not reachable when using the new lazy initialization feature with actuator endpoints exposed on another port than the default one.
Steps to reproduce :
- Create a new project from spring initializr with the new Spring Boot 2.2.0.M1 version
- Add Reactive Web and Actuator dependencies
- Set the properties
management.server.port=8081
andspring.main.lazy-initialization=true
Hit the endpoint http://localhost:8081/actuator/health
and you'll get a connection refused.
Switch off the lazy initialization and the actuator endpoints will be back again. Note that actuator endpoints are working correctly if I switch on the lazy initialization and do not change the management port.
Is something I didn't understand or is there a little bug in the lazy initialization feature ?
By the way, thank you for this feature that I have been waiting for a long time!
Comment From: wilkinsona
Thanks for trying out the milestone. This sounds like a bug to me. We caught a similar one that switched off DevTools restart just before we released but this one slipped through.
Comment From: wilkinsona
Adding the following bean to your app should work around the problem for now:
@Bean
static BeanFactoryPostProcessor ensureEagerManagementServerInitializationPostProcessor() {
return (beanFactory) -> {
String namePrefix = ManagementContextAutoConfiguration.class.getName() + "$";
for (String definitionName : beanFactory.getBeanDefinitionNames()) {
if (definitionName.startsWith(namePrefix)) {
beanFactory.getBeanDefinition(definitionName).setLazyInit(false);
}
}
};
}
This will ensure that the logic that creates the child context for the management server is not lazy and that the server is created and started.
There's a secondary problem here. The beans in the separate management context that's used when the management port does not match the server port are all initialised eagerly. They should be lazy like the main context so that the server is created and listening for requests but, for example, the endpoints are not created until a request is received.
Comment From: wilkinsona
We're going to explore the possibility of looking at the bean's class via the bean definition or the metadata available from the definition and not setting the lazy init flag if, for example, the bean implements SmartInitializingSingleton
.
Comment From: tkvangorder
Is it possible to skip any bean definitions that explicitly set their lazy attribute to false? @Lazy(false)
Comment From: philwebb
@tkvangorder That's a really nice idea, but I think we might need a framework change to be able to do it. Currently AbstractBeanDefinition.lazyInit
is a boolean
so we don't know if the value is false
because that's the default, or if it's because setLazyInit
has been called.
Comment From: jhoeller
We could turn this into a Boolean
field indeed and provide a Boolean getLazyInit()
accessor on AbstractBeanDefinition
... allowing Boot to check whether the flag has been set at all before trying to override it. If this sounds feasible for your purposes, please create a spring-framework issue for it.
Comment From: philwebb
https://github.com/spring-projects/spring-framework/issues/22694 is now fixed
Comment From: mbhave
I've got a fix in a branch here. I was wondering specifically about @wilkinsona's comment
There's a secondary problem here. The beans in the separate management context that's used when the management port does not match the server port are all initialised eagerly. They should be lazy like the main context so that the server is created and listening for requests but, for example, the endpoints are not created until a request is received.
The branch adds a BFPP to the child context for enabling lazy initialization. However, I don't think the creation of endpoints could be delayed till a request is received because of ServletEndpoint
s. The ServletEndpointRegistrar
is a ServletContextInitializer
so that will get initialized early in turn causing early initialization of all the endpoints. It's on a branch in case anyone had a different fix in mind for this.
Comment From: wilkinsona
Thanks for looking at this, @mbhave. There's also a change in DevTools that I made that could perhaps be replaced with some use of @Lazy(false)
.
For the Actuator child context, I wonder if the problem will be solved without @Lazy(false)
if we proceed with #15378. We also talked a bit about trying to detect beans of certain types and not marking them as lazy. That may help with things like Spring Integration's internal components where the user can't add @Lazy(false)
. Perhaps we should consider that as part of a separate issue though?
The fix that you've made for the laziness in the child context was what I had in mind. I hadn't dug into it in much detail and had only realised that the BFPP was only being applied to the parent context.
Comment From: ghost
. That may help with things like Spring Integration's internal components where the user can't add
@Lazy(false)
. Perhaps we should consider that as part of a separate issue though?
Is there a fix for the Spring Integration issue, that would help me resolve issues like the one I am getting here ?
https://stackoverflow.com/questions/60073909/spring-integration-beans-arent-created-when-spring-main-lazy-initialization-tru