Disable Tomcat's MBean Registry by default

Closes gh-16498
pull/16984/head
Andy Wilkinson 6 years ago
parent 080a2f5c3b
commit b603cd5d4b

@ -27,6 +27,7 @@ import org.springframework.boot.autoconfigure.web.embedded.NettyWebServerFactory
import org.springframework.boot.autoconfigure.web.embedded.TomcatWebServerFactoryCustomizer; import org.springframework.boot.autoconfigure.web.embedded.TomcatWebServerFactoryCustomizer;
import org.springframework.boot.autoconfigure.web.embedded.UndertowWebServerFactoryCustomizer; import org.springframework.boot.autoconfigure.web.embedded.UndertowWebServerFactoryCustomizer;
import org.springframework.boot.autoconfigure.web.reactive.ReactiveWebServerFactoryCustomizer; import org.springframework.boot.autoconfigure.web.reactive.ReactiveWebServerFactoryCustomizer;
import org.springframework.boot.autoconfigure.web.reactive.TomcatReactiveWebServerFactoryCustomizer;
import org.springframework.boot.web.reactive.server.ConfigurableReactiveWebServerFactory; import org.springframework.boot.web.reactive.server.ConfigurableReactiveWebServerFactory;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
@ -65,6 +66,7 @@ public class ReactiveManagementChildContextConfiguration {
ReactiveManagementWebServerFactoryCustomizer(ListableBeanFactory beanFactory) { ReactiveManagementWebServerFactoryCustomizer(ListableBeanFactory beanFactory) {
super(beanFactory, ReactiveWebServerFactoryCustomizer.class, super(beanFactory, ReactiveWebServerFactoryCustomizer.class,
TomcatWebServerFactoryCustomizer.class, TomcatWebServerFactoryCustomizer.class,
TomcatReactiveWebServerFactoryCustomizer.class,
JettyWebServerFactoryCustomizer.class, JettyWebServerFactoryCustomizer.class,
UndertowWebServerFactoryCustomizer.class, UndertowWebServerFactoryCustomizer.class,
NettyWebServerFactoryCustomizer.class); NettyWebServerFactoryCustomizer.class);

@ -17,10 +17,12 @@
package org.springframework.boot.actuate.autoconfigure.metrics.web.tomcat; package org.springframework.boot.actuate.autoconfigure.metrics.web.tomcat;
import java.util.Collections; import java.util.Collections;
import java.util.concurrent.atomic.AtomicInteger;
import io.micrometer.core.instrument.MeterRegistry; import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.binder.tomcat.TomcatMetrics; import io.micrometer.core.instrument.binder.tomcat.TomcatMetrics;
import io.micrometer.core.instrument.simple.SimpleMeterRegistry; import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
import org.apache.tomcat.util.modeler.Registry;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
@ -33,11 +35,13 @@ import org.springframework.boot.test.context.runner.ReactiveWebApplicationContex
import org.springframework.boot.test.context.runner.WebApplicationContextRunner; import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
import org.springframework.boot.web.embedded.tomcat.TomcatReactiveWebServerFactory; import org.springframework.boot.web.embedded.tomcat.TomcatReactiveWebServerFactory;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.embedded.tomcat.TomcatWebServer;
import org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext; import org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext;
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext; import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.http.server.reactive.HttpHandler; import org.springframework.http.server.reactive.HttpHandler;
import org.springframework.test.util.ReflectionTestUtils;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
@ -51,6 +55,7 @@ public class TomcatMetricsAutoConfigurationTests {
@Test @Test
public void autoConfiguresTomcatMetricsWithEmbeddedServletTomcat() { public void autoConfiguresTomcatMetricsWithEmbeddedServletTomcat() {
resetTomcatState();
new WebApplicationContextRunner( new WebApplicationContextRunner(
AnnotationConfigServletWebServerApplicationContext::new) AnnotationConfigServletWebServerApplicationContext::new)
.withConfiguration(AutoConfigurations.of( .withConfiguration(AutoConfigurations.of(
@ -58,6 +63,7 @@ public class TomcatMetricsAutoConfigurationTests {
ServletWebServerFactoryAutoConfiguration.class)) ServletWebServerFactoryAutoConfiguration.class))
.withUserConfiguration(ServletWebServerConfiguration.class, .withUserConfiguration(ServletWebServerConfiguration.class,
MeterRegistryConfiguration.class) MeterRegistryConfiguration.class)
.withPropertyValues("server.tomcat.mbeanregistry.enabled=true")
.run((context) -> { .run((context) -> {
context.publishEvent( context.publishEvent(
new ApplicationStartedEvent(new SpringApplication(), new ApplicationStartedEvent(new SpringApplication(),
@ -75,6 +81,7 @@ public class TomcatMetricsAutoConfigurationTests {
@Test @Test
public void autoConfiguresTomcatMetricsWithEmbeddedReactiveTomcat() { public void autoConfiguresTomcatMetricsWithEmbeddedReactiveTomcat() {
resetTomcatState();
new ReactiveWebApplicationContextRunner( new ReactiveWebApplicationContextRunner(
AnnotationConfigReactiveWebServerApplicationContext::new) AnnotationConfigReactiveWebServerApplicationContext::new)
.withConfiguration(AutoConfigurations.of( .withConfiguration(AutoConfigurations.of(
@ -82,6 +89,7 @@ public class TomcatMetricsAutoConfigurationTests {
ReactiveWebServerFactoryAutoConfiguration.class)) ReactiveWebServerFactoryAutoConfiguration.class))
.withUserConfiguration(ReactiveWebServerConfiguration.class, .withUserConfiguration(ReactiveWebServerConfiguration.class,
MeterRegistryConfiguration.class) MeterRegistryConfiguration.class)
.withPropertyValues("server.tomcat.mbeanregistry.enabled=true")
.run((context) -> { .run((context) -> {
context.publishEvent( context.publishEvent(
new ApplicationStartedEvent(new SpringApplication(), new ApplicationStartedEvent(new SpringApplication(),
@ -130,6 +138,13 @@ public class TomcatMetricsAutoConfigurationTests {
.hasBean("customTomcatMetrics")); .hasBean("customTomcatMetrics"));
} }
private void resetTomcatState() {
ReflectionTestUtils.setField(Registry.class, "registry", null);
AtomicInteger containerCounter = (AtomicInteger) ReflectionTestUtils
.getField(TomcatWebServer.class, "containerCounter");
containerCounter.set(-1);
}
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
static class MeterRegistryConfiguration { static class MeterRegistryConfiguration {

@ -23,8 +23,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
import javax.validation.Configuration; import javax.validation.Configuration;
import javax.validation.Validation; import javax.validation.Validation;
import org.apache.catalina.mbeans.MBeanFactory;
import org.springframework.boot.context.event.ApplicationFailedEvent; import org.springframework.boot.context.event.ApplicationFailedEvent;
import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.boot.context.event.ApplicationStartingEvent; import org.springframework.boot.context.event.ApplicationStartingEvent;
@ -99,7 +97,6 @@ public class BackgroundPreinitializer
runSafely(new ConversionServiceInitializer()); runSafely(new ConversionServiceInitializer());
runSafely(new ValidationInitializer()); runSafely(new ValidationInitializer());
runSafely(new MessageConverterInitializer()); runSafely(new MessageConverterInitializer());
runSafely(new MBeanFactoryInitializer());
runSafely(new JacksonInitializer()); runSafely(new JacksonInitializer());
runSafely(new CharsetInitializer()); runSafely(new CharsetInitializer());
preinitializationComplete.countDown(); preinitializationComplete.countDown();
@ -137,18 +134,6 @@ public class BackgroundPreinitializer
} }
/**
* Early initializer to load Tomcat MBean XML.
*/
private static class MBeanFactoryInitializer implements Runnable {
@Override
public void run() {
new MBeanFactory();
}
}
/** /**
* Early initializer for javax.validation. * Early initializer for javax.validation.
*/ */

@ -400,6 +400,11 @@ public class ServerProperties {
*/ */
private final Resource resource = new Resource(); private final Resource resource = new Resource();
/**
* Modeler MBean Registry configuration.
*/
private final Mbeanregistry mbeanregistry = new Mbeanregistry();
public int getMaxThreads() { public int getMaxThreads() {
return this.maxThreads; return this.maxThreads;
} }
@ -552,6 +557,10 @@ public class ServerProperties {
return this.resource; return this.resource;
} }
public Mbeanregistry getMbeanregistry() {
return this.mbeanregistry;
}
/** /**
* Tomcat access log properties. * Tomcat access log properties.
*/ */
@ -821,6 +830,23 @@ public class ServerProperties {
} }
public static class Mbeanregistry {
/**
* Whether Tomcat's MBean Registry should be enabled.
*/
private boolean enabled;
public boolean isEnabled() {
return this.enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
}
} }
/** /**

@ -24,6 +24,7 @@ import reactor.netty.http.server.HttpServer;
import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.web.embedded.jetty.JettyReactiveWebServerFactory; import org.springframework.boot.web.embedded.jetty.JettyReactiveWebServerFactory;
import org.springframework.boot.web.embedded.jetty.JettyServerCustomizer; import org.springframework.boot.web.embedded.jetty.JettyServerCustomizer;
import org.springframework.boot.web.embedded.netty.NettyReactiveWebServerFactory; import org.springframework.boot.web.embedded.netty.NettyReactiveWebServerFactory;
@ -98,6 +99,12 @@ abstract class ReactiveWebServerFactoryConfiguration {
return factory; return factory;
} }
@Bean
public TomcatReactiveWebServerFactoryCustomizer tomcatReactiveWebServerFactoryCustomizer(
ServerProperties serverProperties) {
return new TomcatReactiveWebServerFactoryCustomizer(serverProperties);
}
} }
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)

@ -0,0 +1,48 @@
/*
* Copyright 2012-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.web.reactive;
import org.apache.tomcat.util.modeler.Registry;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.web.embedded.tomcat.TomcatReactiveWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
/**
* {@link WebServerFactoryCustomizer} to apply {@link ServerProperties} to Tomcat reactive
* web servers.
*
* @author Andy Wilkinson
* @since 2.2.0
*/
public class TomcatReactiveWebServerFactoryCustomizer
implements WebServerFactoryCustomizer<TomcatReactiveWebServerFactory> {
private final ServerProperties serverProperties;
public TomcatReactiveWebServerFactoryCustomizer(ServerProperties serverProperties) {
this.serverProperties = serverProperties;
}
@Override
public void customize(TomcatReactiveWebServerFactory factory) {
if (!this.serverProperties.getTomcat().getMbeanregistry().isEnabled()) {
Registry.disableRegistry();
}
}
}

@ -16,6 +16,8 @@
package org.springframework.boot.autoconfigure.web.servlet; package org.springframework.boot.autoconfigure.web.servlet;
import org.apache.tomcat.util.modeler.Registry;
import org.springframework.boot.autoconfigure.web.ServerProperties; import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.web.embedded.tomcat.ConfigurableTomcatWebServerFactory; import org.springframework.boot.web.embedded.tomcat.ConfigurableTomcatWebServerFactory;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
@ -60,6 +62,9 @@ public class TomcatServletWebServerFactoryCustomizer
customizeUseRelativeRedirects(factory, customizeUseRelativeRedirects(factory,
tomcatProperties.getUseRelativeRedirects()); tomcatProperties.getUseRelativeRedirects());
} }
if (!tomcatProperties.getMbeanregistry().isEnabled()) {
Registry.disableRegistry();
}
} }
private void customizeRedirectContextRoot(ConfigurableTomcatWebServerFactory factory, private void customizeRedirectContextRoot(ConfigurableTomcatWebServerFactory factory,

@ -1075,6 +1075,20 @@ include::{code-examples}/context/embedded/TomcatLegacyCookieProcessorExample.jav
[[howto-enable-tomcat-mbean-registry]]
=== Enable Tomcat's MBean Registry
Embedded Tomcat's MBean registry is disabled by default. This minimizes Tomcat's memory
footprint. If you want to use Tomcat's MBeans, for example so that they can be used to
expose metrics via Micrometer, you must use the `server.tomcat.mbeanregistry.enabled`
property to do so, as shown in the following example:
[source,properties,indent=0]
----
server.tomcat.mbeanregistry.enabled=true
----
[[howto-enable-multiple-listeners-in-undertow]] [[howto-enable-multiple-listeners-in-undertow]]
=== Enable Multiple Listeners with Undertow === Enable Multiple Listeners with Undertow
Add an `UndertowBuilderCustomizer` to the `UndertowServletWebServerFactory` and Add an `UndertowBuilderCustomizer` to the `UndertowServletWebServerFactory` and

@ -1793,7 +1793,8 @@ Spring Boot registers the following core metrics when applicable:
* Logback metrics: record the number of events logged to Logback at each level * Logback metrics: record the number of events logged to Logback at each level
* Uptime metrics: report a gauge for uptime and a fixed gauge representing the * Uptime metrics: report a gauge for uptime and a fixed gauge representing the
application's absolute start time application's absolute start time
* Tomcat metrics * Tomcat metrics (`server.tomcat.mbeanregistry.enabled` must be set to `true` for all
Tomcat metrics to be registered)
* https://docs.spring.io/spring-integration/docs/current/reference/html/system-management-chapter.html#micrometer-integration[Spring Integration] metrics * https://docs.spring.io/spring-integration/docs/current/reference/html/system-management-chapter.html#micrometer-integration[Spring Integration] metrics

Loading…
Cancel
Save