Spring Boot customize server.tomcat.threads.min-spare for management server only

Viewed 483

I have an application with management.server enabled:

management.server.port=8081

When I start application, I have:

  • 10 threads for 8080 HTTP nio connector
  • 10 threads for 8081 HTTP nio connector

But I would like to reduce min-spare only for management (8081) and not for the web application (8080)

Looking at Spring code, it seems it's not possible, can someone confirm ?

3 Answers

EDIT: The approach below is not sufficient as the ManagementWebServerFactoryCustomizer is also a ConfigurableWebServerFactory and will thus be applied to the main server. Adding logic to check againgst the management port is not helping as the management context has its very own wiring and won't pick up the bean.

Looks like it's not possible to hook into the management server configuration easily (would be easier if ServletManagementContextFactory were public).


You can look into ServletManagementChildContextConfiguration to see how the management server is wired.

You could hook into the management server configuration by providing a ManagementWebServerFactoryCustomizer like this (not sure if there's an easier way):

@Configuration
public class TomcatManagementCustomizerConfiguration {
    
    @Bean
    ManagementWebServerFactoryCustomizer<ConfigurableServletWebServerFactory> servletManagementWebServerFactoryCustomizer(
            @Value("${management.server.threads.min-spare:5}") int managementMinSpareThreads,
            ListableBeanFactory beanFactory) {
        return new TomcatManagementCustomizer(beanFactory, managementMinSpareThreads);
    }
    
    static class TomcatManagementCustomizer extends ManagementWebServerFactoryCustomizer<ConfigurableServletWebServerFactory> {
        private final int managementMinSpareThreads;

        protected TomcatManagementCustomizer(ListableBeanFactory beanFactory, int managementMinSpareThreads) {
            super(beanFactory, TomcatWebServerFactoryCustomizer.class);
            this.managementMinSpareThreads = managementMinSpareThreads;
        }

        @Override
        @SuppressWarnings("rawtypes")
        protected void customize(ConfigurableServletWebServerFactory factory, ManagementServerProperties managementServerProperties, ServerProperties serverProperties) {
            super.customize(factory, managementServerProperties, serverProperties);
            ((TomcatServletWebServerFactory) factory).addConnectorCustomizers((connector) -> {
                ProtocolHandler handler = connector.getProtocolHandler();
                if (handler instanceof AbstractProtocol) {
                    AbstractProtocol protocol = (AbstractProtocol) handler;
                    protocol.setMinSpareThreads(managementMinSpareThreads);
                }
            });
        }
    }
}

Can you not just put the following in either properties file or YAML file?
Or is there something I misunderstood?

server.tomcat.threads.min-spare=2
(This is for properties file)

Just to verify (You don't need this as you have been checking the updated value in the log)

Put the following in either properties file or YAML file

management.endpoints.web.exposure.include=health,info,metrics,env
(This is for properties file)

And visit /actuator/env/server.tomcat.threads.min-spare
You need actuator dependency for the link above to work.

You can use @ManagementConfigurationContext and add the configuration class to to your META-INF/spring.properties file.

It is also important to place the configuration class in a package which is not the main package or sub-package of your main application context. This is so that this configuration only applies to the management context.

Below is the sampel configuration following @Holgzn's response.

@ManagementContextConfiguration
public class TomcatManagementCustomizerConfiguration {
    
    @Bean
    ManagementWebServerFactoryCustomizer<ConfigurableServletWebServerFactory> servletManagementWebServerFactoryCustomizer(
            @Value("${management.server.threads.min-spare:5}") int managementMinSpareThreads,
            ListableBeanFactory beanFactory) {
        return new TomcatManagementCustomizer(beanFactory, managementMinSpareThreads);
    }
    
    static class TomcatManagementCustomizer extends ManagementWebServerFactoryCustomizer<ConfigurableServletWebServerFactory> {
        private final int managementMinSpareThreads;

        protected TomcatManagementCustomizer(ListableBeanFactory beanFactory, int managementMinSpareThreads) {
            super(beanFactory, TomcatWebServerFactoryCustomizer.class);
            this.managementMinSpareThreads = managementMinSpareThreads;
        }

        @Override
        @SuppressWarnings("rawtypes")
        protected void customize(ConfigurableServletWebServerFactory factory, ManagementServerProperties managementServerProperties, ServerProperties serverProperties) {
            super.customize(factory, managementServerProperties, serverProperties);
            ((TomcatServletWebServerFactory) factory).addConnectorCustomizers((connector) -> {
                ProtocolHandler handler = connector.getProtocolHandler();
                if (handler instanceof AbstractProtocol) {
                    AbstractProtocol protocol = (AbstractProtocol) handler;
                    protocol.setMinSpareThreads(managementMinSpareThreads);
                }
            });
        }
    }
}

The spring.properties file

org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration=<package>.TomcatManagementCustomizerConfiguration 
Related