Skip to content

Commit 4cb47eb

Browse files
committed
Move server-specific knowledge out of general child context creation
Issue: 44200
1 parent 361895b commit 4cb47eb

18 files changed

+645
-288
lines changed

spring-boot-project/spring-boot-actuator-autoconfigure/build.gradle

+1
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ dependencies {
6666
optional("io.r2dbc:r2dbc-pool")
6767
optional("io.r2dbc:r2dbc-proxy")
6868
optional("io.r2dbc:r2dbc-spi")
69+
optional("io.undertow:undertow-servlet")
6970
optional("jakarta.jms:jakarta.jms-api")
7071
optional("jakarta.persistence:jakarta.persistence-api")
7172
optional("jakarta.servlet:jakarta.servlet-api")

spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/reactive/ReactiveManagementChildContextConfiguration.java

-132
Original file line numberDiff line numberDiff line change
@@ -16,33 +16,19 @@
1616

1717
package org.springframework.boot.actuate.autoconfigure.web.reactive;
1818

19-
import java.io.File;
2019
import java.util.Collections;
2120
import java.util.Map;
2221

23-
import org.apache.catalina.Valve;
24-
import org.apache.catalina.valves.AccessLogValve;
25-
import org.eclipse.jetty.server.CustomRequestLog;
26-
import org.eclipse.jetty.server.RequestLog;
27-
import org.eclipse.jetty.server.RequestLogWriter;
28-
import org.eclipse.jetty.server.Server;
29-
3022
import org.springframework.beans.factory.ListableBeanFactory;
3123
import org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration;
3224
import org.springframework.boot.actuate.autoconfigure.web.ManagementContextType;
3325
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementServerProperties;
3426
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementWebServerFactoryCustomizer;
35-
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
3627
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
3728
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
38-
import org.springframework.boot.web.embedded.jetty.JettyReactiveWebServerFactory;
39-
import org.springframework.boot.web.embedded.tomcat.TomcatReactiveWebServerFactory;
40-
import org.springframework.boot.web.embedded.undertow.UndertowReactiveWebServerFactory;
4129
import org.springframework.boot.web.server.ConfigurableWebServerFactory;
42-
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
4330
import org.springframework.context.ApplicationContext;
4431
import org.springframework.context.annotation.Bean;
45-
import org.springframework.core.Ordered;
4632
import org.springframework.http.server.reactive.ContextPathCompositeHandler;
4733
import org.springframework.http.server.reactive.HttpHandler;
4834
import org.springframework.util.StringUtils;
@@ -79,122 +65,4 @@ public HttpHandler httpHandler(ApplicationContext applicationContext, Management
7965
return httpHandler;
8066
}
8167

82-
@Bean
83-
@ConditionalOnClass(name = "io.undertow.Undertow")
84-
UndertowAccessLogCustomizer undertowManagementAccessLogCustomizer(ManagementServerProperties properties) {
85-
return new UndertowAccessLogCustomizer(properties);
86-
}
87-
88-
@Bean
89-
@ConditionalOnClass(name = "org.apache.catalina.valves.AccessLogValve")
90-
TomcatAccessLogCustomizer tomcatManagementAccessLogCustomizer(ManagementServerProperties properties) {
91-
return new TomcatAccessLogCustomizer(properties);
92-
}
93-
94-
@Bean
95-
@ConditionalOnClass(name = "org.eclipse.jetty.server.Server")
96-
JettyAccessLogCustomizer jettyManagementAccessLogCustomizer(ManagementServerProperties properties) {
97-
return new JettyAccessLogCustomizer(properties);
98-
}
99-
100-
abstract static class AccessLogCustomizer implements Ordered {
101-
102-
private final ManagementServerProperties properties;
103-
104-
AccessLogCustomizer(ManagementServerProperties properties) {
105-
this.properties = properties;
106-
}
107-
108-
protected String customizePrefix(String prefix) {
109-
prefix = (prefix != null) ? prefix : "";
110-
if (prefix.startsWith(this.properties.getAccesslog().getPrefix())) {
111-
return prefix;
112-
}
113-
return this.properties.getAccesslog().getPrefix() + prefix;
114-
}
115-
116-
@Override
117-
public int getOrder() {
118-
return 1;
119-
}
120-
121-
}
122-
123-
static class TomcatAccessLogCustomizer extends AccessLogCustomizer
124-
implements WebServerFactoryCustomizer<TomcatReactiveWebServerFactory> {
125-
126-
TomcatAccessLogCustomizer(ManagementServerProperties properties) {
127-
super(properties);
128-
}
129-
130-
@Override
131-
public void customize(TomcatReactiveWebServerFactory factory) {
132-
AccessLogValve accessLogValve = findAccessLogValve(factory);
133-
if (accessLogValve == null) {
134-
return;
135-
}
136-
accessLogValve.setPrefix(customizePrefix(accessLogValve.getPrefix()));
137-
}
138-
139-
private AccessLogValve findAccessLogValve(TomcatReactiveWebServerFactory factory) {
140-
for (Valve engineValve : factory.getEngineValves()) {
141-
if (engineValve instanceof AccessLogValve accessLogValve) {
142-
return accessLogValve;
143-
}
144-
}
145-
return null;
146-
}
147-
148-
}
149-
150-
static class UndertowAccessLogCustomizer extends AccessLogCustomizer
151-
implements WebServerFactoryCustomizer<UndertowReactiveWebServerFactory> {
152-
153-
UndertowAccessLogCustomizer(ManagementServerProperties properties) {
154-
super(properties);
155-
}
156-
157-
@Override
158-
public void customize(UndertowReactiveWebServerFactory factory) {
159-
factory.setAccessLogPrefix(customizePrefix(factory.getAccessLogPrefix()));
160-
}
161-
162-
}
163-
164-
static class JettyAccessLogCustomizer extends AccessLogCustomizer
165-
implements WebServerFactoryCustomizer<JettyReactiveWebServerFactory> {
166-
167-
JettyAccessLogCustomizer(ManagementServerProperties properties) {
168-
super(properties);
169-
}
170-
171-
@Override
172-
public void customize(JettyReactiveWebServerFactory factory) {
173-
factory.addServerCustomizers(this::customizeServer);
174-
}
175-
176-
private void customizeServer(Server server) {
177-
RequestLog requestLog = server.getRequestLog();
178-
if (requestLog instanceof CustomRequestLog customRequestLog) {
179-
customizeRequestLog(customRequestLog);
180-
}
181-
}
182-
183-
private void customizeRequestLog(CustomRequestLog requestLog) {
184-
if (requestLog.getWriter() instanceof RequestLogWriter requestLogWriter) {
185-
customizeRequestLogWriter(requestLogWriter);
186-
}
187-
}
188-
189-
private void customizeRequestLogWriter(RequestLogWriter writer) {
190-
String filename = writer.getFileName();
191-
if (StringUtils.hasLength(filename)) {
192-
File file = new File(filename);
193-
file = new File(file.getParentFile(), customizePrefix(file.getName()));
194-
writer.setFilename(file.getPath());
195-
}
196-
}
197-
198-
}
199-
20068
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*
2+
* Copyright 2012-2025 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.actuate.autoconfigure.web.server;
18+
19+
import org.springframework.boot.web.server.WebServerFactory;
20+
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
21+
import org.springframework.core.Ordered;
22+
23+
/**
24+
* Base class for a {@link WebServerFactoryCustomizer} that customizes the web server's
25+
* access log.
26+
*
27+
* @param <T> the {@link WebServerFactory} type that can be customized
28+
* @author Andy Wilkinson
29+
* @since 4.0.0
30+
*/
31+
public abstract class AccessLogCustomizer<T extends WebServerFactory>
32+
implements WebServerFactoryCustomizer<T>, Ordered {
33+
34+
private final ManagementServerProperties properties;
35+
36+
protected AccessLogCustomizer(ManagementServerProperties properties) {
37+
this.properties = properties;
38+
}
39+
40+
protected String customizePrefix(String prefix) {
41+
prefix = (prefix != null) ? prefix : "";
42+
if (prefix.startsWith(this.properties.getAccesslog().getPrefix())) {
43+
return prefix;
44+
}
45+
return this.properties.getAccesslog().getPrefix() + prefix;
46+
}
47+
48+
@Override
49+
public int getOrder() {
50+
return 1;
51+
}
52+
53+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/*
2+
* Copyright 2012-2025 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.actuate.autoconfigure.web.server.jetty;
18+
19+
import java.io.File;
20+
21+
import org.eclipse.jetty.server.CustomRequestLog;
22+
import org.eclipse.jetty.server.RequestLog;
23+
import org.eclipse.jetty.server.RequestLogWriter;
24+
import org.eclipse.jetty.server.Server;
25+
26+
import org.springframework.boot.actuate.autoconfigure.web.server.AccessLogCustomizer;
27+
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementServerProperties;
28+
import org.springframework.boot.web.embedded.jetty.ConfigurableJettyWebServerFactory;
29+
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
30+
import org.springframework.util.StringUtils;
31+
32+
/**
33+
* {@link AccessLogCustomizer} for Jetty.
34+
*
35+
* @author Andy Wilkinson
36+
*/
37+
class JettyAccessLogCustomizer extends AccessLogCustomizer<ConfigurableJettyWebServerFactory>
38+
implements WebServerFactoryCustomizer<ConfigurableJettyWebServerFactory> {
39+
40+
JettyAccessLogCustomizer(ManagementServerProperties properties) {
41+
super(properties);
42+
}
43+
44+
@Override
45+
public void customize(ConfigurableJettyWebServerFactory factory) {
46+
factory.addServerCustomizers(this::customizeServer);
47+
}
48+
49+
private void customizeServer(Server server) {
50+
RequestLog requestLog = server.getRequestLog();
51+
if (requestLog instanceof CustomRequestLog customRequestLog) {
52+
customizeRequestLog(customRequestLog);
53+
}
54+
}
55+
56+
private void customizeRequestLog(CustomRequestLog requestLog) {
57+
if (requestLog.getWriter() instanceof RequestLogWriter requestLogWriter) {
58+
customizeRequestLogWriter(requestLogWriter);
59+
}
60+
}
61+
62+
private void customizeRequestLogWriter(RequestLogWriter writer) {
63+
String filename = writer.getFileName();
64+
if (StringUtils.hasLength(filename)) {
65+
File file = new File(filename);
66+
file = new File(file.getParentFile(), customizePrefix(file.getName()));
67+
writer.setFilename(file.getPath());
68+
}
69+
}
70+
71+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
* Copyright 2012-2025 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.actuate.autoconfigure.web.server.jetty;
18+
19+
import org.eclipse.jetty.server.Server;
20+
21+
import org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration;
22+
import org.springframework.boot.actuate.autoconfigure.web.ManagementContextType;
23+
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementServerProperties;
24+
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
25+
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
26+
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
27+
import org.springframework.boot.context.properties.EnableConfigurationProperties;
28+
import org.springframework.context.annotation.Bean;
29+
30+
/**
31+
* {@link ManagementContextConfiguration @ManagementContextConfiguration} for Jetty-based
32+
* reactive web endpoint infrastructure when a separate management context running on a
33+
* different port is required.
34+
*
35+
* @author Andy Wilkinson
36+
*/
37+
@ConditionalOnClass(Server.class)
38+
@ConditionalOnWebApplication(type = Type.REACTIVE)
39+
@EnableConfigurationProperties(ManagementServerProperties.class)
40+
@ManagementContextConfiguration(value = ManagementContextType.CHILD, proxyBeanMethods = false)
41+
class JettyReactiveManagementChildContextConfiguration {
42+
43+
@Bean
44+
JettyAccessLogCustomizer jettyManagementAccessLogCustomizer(ManagementServerProperties properties) {
45+
return new JettyAccessLogCustomizer(properties);
46+
}
47+
48+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
* Copyright 2012-2025 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.actuate.autoconfigure.web.server.jetty;
18+
19+
import org.eclipse.jetty.server.Server;
20+
21+
import org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration;
22+
import org.springframework.boot.actuate.autoconfigure.web.ManagementContextType;
23+
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementServerProperties;
24+
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
25+
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
26+
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
27+
import org.springframework.boot.context.properties.EnableConfigurationProperties;
28+
import org.springframework.context.annotation.Bean;
29+
30+
/**
31+
* {@link ManagementContextConfiguration @ManagementContextConfiguration} for Jetty-based
32+
* servlet web endpoint infrastructure when a separate management context running on a
33+
* different port is required.
34+
*
35+
* @author Andy Wilkinson
36+
*/
37+
@ConditionalOnClass(Server.class)
38+
@ConditionalOnWebApplication(type = Type.SERVLET)
39+
@EnableConfigurationProperties(ManagementServerProperties.class)
40+
@ManagementContextConfiguration(value = ManagementContextType.CHILD, proxyBeanMethods = false)
41+
class JettyServletManagementChildContextConfiguration {
42+
43+
@Bean
44+
JettyAccessLogCustomizer jettyManagementAccessLogCustomizer(ManagementServerProperties properties) {
45+
return new JettyAccessLogCustomizer(properties);
46+
}
47+
48+
}

0 commit comments

Comments
 (0)