Skip to content

Commit 7dd3a34

Browse files
committed
Modify ActuatorProvider and subtypes WebMvc, WebFlux to work on a deployed webserver
1 parent 0cf0153 commit 7dd3a34

File tree

10 files changed

+279
-65
lines changed

10 files changed

+279
-65
lines changed

.github/workflows/maven.yml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time
2+
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-maven
3+
4+
# This workflow uses actions that are not certified by GitHub.
5+
# They are provided by a third-party and are governed by
6+
# separate terms of service, privacy policy, and support
7+
# documentation.
8+
9+
name: Java CI with Maven
10+
11+
on:
12+
push:
13+
pull_request:
14+
15+
jobs:
16+
build:
17+
18+
runs-on: ubuntu-latest
19+
20+
steps:
21+
- uses: actions/checkout@v4
22+
- name: Set up JDK 21
23+
uses: actions/setup-java@v4
24+
with:
25+
java-version: '21'
26+
distribution: 'temurin'
27+
cache: maven
28+
- name: Build with Maven
29+
run: mvn -B package --file pom.xml
30+
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
package org.springdoc.core.configuration;
2+
3+
import java.util.function.Supplier;
4+
5+
import org.apache.commons.lang3.StringUtils;
6+
import org.springframework.beans.factory.ObjectProvider;
7+
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
8+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
9+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
10+
import org.springframework.boot.web.server.WebServer;
11+
import org.springframework.boot.web.server.autoconfigure.ServerProperties;
12+
import org.springframework.boot.web.server.context.WebServerApplicationContext;
13+
import org.springframework.boot.web.server.context.WebServerInitializedEvent;
14+
import org.springframework.context.ApplicationContext;
15+
import org.springframework.context.ApplicationListener;
16+
import org.springframework.context.annotation.Bean;
17+
import org.springframework.context.annotation.Configuration;
18+
19+
import static org.apache.commons.lang3.StringUtils.EMPTY;
20+
21+
public class SpringDocWebServerConfiguration {
22+
23+
/**
24+
* WebServer context
25+
*/
26+
public interface SpringDocWebServerContext {
27+
Supplier<Integer> getApplicationPort();
28+
29+
Supplier<Integer> getActuatorPort();
30+
31+
Supplier<ApplicationContext> getManagementApplicationContext();
32+
33+
String getContextPath();
34+
}
35+
36+
@Configuration(proxyBeanMethods = false)
37+
@ConditionalOnClass({WebServerInitializedEvent.class, ServerProperties.class})
38+
static class EmbeddedWebServerConfiguration {
39+
40+
@Bean
41+
SpringDocWebServerContext webServerPortProvider(ObjectProvider<ServerProperties> serverPropertiesProvider) {
42+
return new SpringDocWebServerPortListener(serverPropertiesProvider);
43+
}
44+
45+
static final class SpringDocWebServerPortListener
46+
implements ApplicationListener<WebServerInitializedEvent>,
47+
SpringDocWebServerContext {
48+
49+
private final String contextPath;
50+
51+
private volatile Supplier<Integer> applicationPortSupplier;
52+
private volatile Supplier<Integer> actuatorPortSupplier;
53+
private volatile Supplier<ApplicationContext> managementContextSupplier;
54+
55+
public SpringDocWebServerPortListener(ObjectProvider<ServerProperties> serverPropertiesProvider) {
56+
ServerProperties serverProperties = serverPropertiesProvider.getIfAvailable();
57+
contextPath = serverProperties != null
58+
? StringUtils.defaultIfEmpty(serverProperties.getServlet().getContextPath(), EMPTY)
59+
: EMPTY;
60+
}
61+
62+
@Override
63+
public void onApplicationEvent(WebServerInitializedEvent event) {
64+
final WebServer webServer = event.getWebServer();
65+
if (WebServerApplicationContext.hasServerNamespace(event.getApplicationContext(), "management")) {
66+
this.actuatorPortSupplier = webServer::getPort;
67+
this.managementContextSupplier = event::getApplicationContext;
68+
}
69+
else {
70+
this.applicationPortSupplier = webServer::getPort;
71+
}
72+
}
73+
74+
@Override
75+
public Supplier<Integer> getApplicationPort() {
76+
return applicationPortSupplier;
77+
}
78+
79+
@Override
80+
public Supplier<Integer> getActuatorPort() {
81+
return actuatorPortSupplier;
82+
}
83+
84+
@Override
85+
public Supplier<ApplicationContext> getManagementApplicationContext() {
86+
return this.managementContextSupplier;
87+
}
88+
89+
@Override
90+
public String getContextPath() {
91+
return contextPath;
92+
}
93+
94+
}
95+
}
96+
97+
@Configuration(proxyBeanMethods = false)
98+
@ConditionalOnMissingClass({"org.springframework.boot.web.server.context.WebServerInitializedEvent", "org.springframework.boot.web.server.autoconfigure.ServerProperties"})
99+
static class DeployedWebServerConfiguration {
100+
101+
@Bean
102+
@ConditionalOnMissingBean(SpringDocWebServerContext.class)
103+
SpringDocWebServerContext webServerPortProvider() {
104+
return new SpringDocWebServerContext() {
105+
@Override
106+
public Supplier<Integer> getApplicationPort() {
107+
return () -> -1;
108+
}
109+
110+
@Override
111+
public Supplier<Integer> getActuatorPort() {
112+
return () -> -1;
113+
}
114+
115+
@Override
116+
public Supplier<ApplicationContext> getManagementApplicationContext() {
117+
return () -> null;
118+
}
119+
120+
@Override
121+
public String getContextPath() {
122+
return EMPTY;
123+
}
124+
};
125+
}
126+
}
127+
}

springdoc-openapi-starter-common/src/main/java/org/springdoc/core/providers/ActuatorProvider.java

Lines changed: 11 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -32,19 +32,15 @@
3232
import io.swagger.v3.oas.models.ExternalDocumentation;
3333
import io.swagger.v3.oas.models.tags.Tag;
3434
import org.springdoc.api.AbstractOpenApiResource;
35+
import org.springdoc.core.configuration.SpringDocWebServerConfiguration;
3536
import org.springdoc.core.properties.SpringDocConfigProperties;
3637
import org.springdoc.core.utils.Constants;
3738

3839
import org.springframework.beans.BeansException;
3940
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties;
4041
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementServerProperties;
41-
import org.springframework.boot.web.server.WebServer;
42-
import org.springframework.boot.web.server.autoconfigure.ServerProperties;
43-
import org.springframework.boot.web.server.context.WebServerApplicationContext;
44-
import org.springframework.boot.web.server.context.WebServerInitializedEvent;
4542
import org.springframework.context.ApplicationContext;
4643
import org.springframework.context.ApplicationContextAware;
47-
import org.springframework.context.ApplicationListener;
4844
import org.springframework.util.AntPathMatcher;
4945
import org.springframework.web.method.HandlerMethod;
5046

@@ -56,7 +52,7 @@
5652
*
5753
* @author bnasslahsen
5854
*/
59-
public abstract class ActuatorProvider implements ApplicationListener<WebServerInitializedEvent>, ApplicationContextAware {
55+
public abstract class ActuatorProvider implements ApplicationContextAware {
6056

6157
/**
6258
* The Management server properties.
@@ -68,31 +64,17 @@ public abstract class ActuatorProvider implements ApplicationListener<WebServerI
6864
*/
6965
protected WebEndpointProperties webEndpointProperties;
7066

67+
7168
/**
72-
* The Server properties.
73-
*/
74-
protected ServerProperties serverProperties;
69+
* The server context
70+
*/
71+
protected SpringDocWebServerConfiguration.SpringDocWebServerContext springDocWebServerContext;
7572

7673
/**
7774
* The Spring doc config properties.
7875
*/
7976
protected SpringDocConfigProperties springDocConfigProperties;
8077

81-
/**
82-
* The Actuator web server.
83-
*/
84-
protected WebServer actuatorWebServer;
85-
86-
/**
87-
* The Application web server.
88-
*/
89-
protected WebServer applicationWebServer;
90-
91-
/**
92-
* The Management application context.
93-
*/
94-
protected ApplicationContext managementApplicationContext;
95-
9678
/**
9779
* The Application context.
9880
*/
@@ -103,19 +85,19 @@ public abstract class ActuatorProvider implements ApplicationListener<WebServerI
10385
*
10486
* @param managementServerProperties the management server properties
10587
* @param webEndpointProperties the web endpoint properties
106-
* @param serverProperties the server properties
88+
* @param springDocWebServerContext the server context
10789
* @param springDocConfigProperties the spring doc config properties
10890
*/
10991
protected ActuatorProvider(Optional<ManagementServerProperties> managementServerProperties,
11092
Optional<WebEndpointProperties> webEndpointProperties,
111-
ServerProperties serverProperties,
93+
SpringDocWebServerConfiguration.SpringDocWebServerContext springDocWebServerContext,
11294
SpringDocConfigProperties springDocConfigProperties) {
11395

11496
managementServerProperties.ifPresent(managementServerProperties1 -> this.managementServerProperties = managementServerProperties1);
11597
webEndpointProperties.ifPresent(webEndpointProperties1 -> this.webEndpointProperties = webEndpointProperties1);
11698

117-
this.serverProperties = serverProperties;
11899
this.springDocConfigProperties = springDocConfigProperties;
100+
this.springDocWebServerContext = springDocWebServerContext;
119101
}
120102

121103
/**
@@ -135,16 +117,6 @@ public static Tag getTag() {
135117
return actuatorTag;
136118
}
137119

138-
@Override
139-
public void onApplicationEvent(WebServerInitializedEvent event) {
140-
if (WebServerApplicationContext.hasServerNamespace(event.getApplicationContext(), "management")) {
141-
managementApplicationContext = event.getApplicationContext();
142-
actuatorWebServer = event.getWebServer();
143-
}
144-
else {
145-
applicationWebServer = event.getWebServer();
146-
}
147-
}
148120

149121
/**
150122
* Is rest controller boolean.
@@ -201,7 +173,7 @@ public String getActuatorPath() {
201173
* @return the application port
202174
*/
203175
public int getApplicationPort() {
204-
return applicationWebServer.getPort();
176+
return this.springDocWebServerContext.getApplicationPort().get();
205177
}
206178

207179
/**
@@ -210,7 +182,7 @@ public int getApplicationPort() {
210182
* @return the actuator port
211183
*/
212184
public int getActuatorPort() {
213-
return actuatorWebServer.getPort();
185+
return this.springDocWebServerContext.getActuatorPort().get();
214186
}
215187

216188
/**

springdoc-openapi-starter-common/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,6 @@ org.springdoc.core.configuration.SpringDocSpecPropertiesConfiguration
1111
org.springdoc.core.configuration.SpringDocDataRestConfiguration
1212
org.springdoc.core.configuration.SpringDocKotlinConfiguration
1313
org.springdoc.core.configuration.SpringDocKotlinxConfiguration
14-
org.springdoc.core.configuration.SpringDocJacksonKotlinModuleConfiguration
14+
org.springdoc.core.configuration.SpringDocJacksonKotlinModuleConfiguration
15+
org.springdoc.core.configuration.SpringDocWebServerConfiguration.EmbeddedWebServerConfiguration
16+
org.springdoc.core.configuration.SpringDocWebServerConfiguration.DeployedWebServerConfiguration

springdoc-openapi-starter-webflux-api/src/main/java/org/springdoc/webflux/core/configuration/SpringDocWebFluxConfiguration.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import java.util.Optional;
3030

3131
import org.springdoc.core.configuration.SpringDocConfiguration;
32+
import org.springdoc.core.configuration.SpringDocWebServerConfiguration;
3233
import org.springdoc.core.customizers.SpringDocCustomizers;
3334
import org.springdoc.core.discoverer.SpringDocParameterNameDiscoverer;
3435
import org.springdoc.core.extractor.MethodParameterPojoExtractor;
@@ -60,7 +61,6 @@
6061
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
6162
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
6263
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
63-
import org.springframework.boot.web.server.autoconfigure.ServerProperties;
6464
import org.springframework.boot.webflux.actuate.endpoint.web.WebFluxEndpointHandlerMapping;
6565
import org.springframework.context.annotation.Bean;
6666
import org.springframework.context.annotation.Configuration;
@@ -165,7 +165,7 @@ static class SpringDocWebFluxActuatorConfiguration {
165165
/**
166166
* Actuator provider actuator provider.
167167
*
168-
* @param serverProperties the server properties
168+
* @param springDocWebServerContext the server context
169169
* @param springDocConfigProperties the spring doc config properties
170170
* @param managementServerProperties the management server properties
171171
* @param webEndpointProperties the web endpoint properties
@@ -175,11 +175,11 @@ static class SpringDocWebFluxActuatorConfiguration {
175175
@ConditionalOnMissingBean
176176
@ConditionalOnExpression("${springdoc.show-actuator:false} or ${springdoc.use-management-port:false}")
177177
@Lazy(false)
178-
ActuatorProvider actuatorProvider(ServerProperties serverProperties,
178+
ActuatorProvider actuatorProvider(SpringDocWebServerConfiguration.SpringDocWebServerContext springDocWebServerContext,
179179
SpringDocConfigProperties springDocConfigProperties,
180180
Optional<ManagementServerProperties> managementServerProperties,
181181
Optional<WebEndpointProperties> webEndpointProperties) {
182-
return new ActuatorWebFluxProvider(serverProperties,
182+
return new ActuatorWebFluxProvider(springDocWebServerContext,
183183
springDocConfigProperties,
184184
managementServerProperties,
185185
webEndpointProperties);

springdoc-openapi-starter-webflux-api/src/main/java/org/springdoc/webflux/core/providers/ActuatorWebFluxProvider.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,12 @@
3030
import java.util.Map;
3131
import java.util.Optional;
3232

33+
import org.springdoc.core.configuration.SpringDocWebServerConfiguration;
3334
import org.springdoc.core.properties.SpringDocConfigProperties;
3435
import org.springdoc.core.providers.ActuatorProvider;
3536

3637
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties;
3738
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementServerProperties;
38-
import org.springframework.boot.web.server.autoconfigure.ServerProperties;
3939
import org.springframework.boot.webflux.actuate.endpoint.web.ControllerEndpointHandlerMapping;
4040
import org.springframework.boot.webflux.actuate.endpoint.web.WebFluxEndpointHandlerMapping;
4141
import org.springframework.context.ApplicationContextAware;
@@ -54,29 +54,29 @@ public class ActuatorWebFluxProvider extends ActuatorProvider implements Applica
5454
/**
5555
* Instantiates a new Actuator web flux provider.
5656
*
57-
* @param serverProperties the server properties
57+
* @param springDocWebServerContext the server context
5858
* @param springDocConfigProperties the spring doc config properties
5959
* @param managementServerProperties the management server properties
6060
* @param webEndpointProperties the web endpoint properties
6161
*/
62-
public ActuatorWebFluxProvider(ServerProperties serverProperties,
62+
public ActuatorWebFluxProvider(SpringDocWebServerConfiguration.SpringDocWebServerContext springDocWebServerContext,
6363
SpringDocConfigProperties springDocConfigProperties,
6464
Optional<ManagementServerProperties> managementServerProperties,
6565
Optional<WebEndpointProperties> webEndpointProperties) {
66-
super(managementServerProperties, webEndpointProperties, serverProperties, springDocConfigProperties);
66+
super(managementServerProperties, webEndpointProperties, springDocWebServerContext, springDocConfigProperties);
6767
}
6868

6969
public Map<RequestMappingInfo, HandlerMethod> getMethods() {
7070
Map<RequestMappingInfo, HandlerMethod> mappingInfoHandlerMethodMap = new HashMap<>();
7171

7272
WebFluxEndpointHandlerMapping webFluxEndpointHandlerMapping = applicationContext.getBeansOfType(WebFluxEndpointHandlerMapping.class).values().stream().findFirst().orElse(null);
7373
if (webFluxEndpointHandlerMapping == null)
74-
webFluxEndpointHandlerMapping = managementApplicationContext.getBean(WebFluxEndpointHandlerMapping.class);
74+
webFluxEndpointHandlerMapping = springDocWebServerContext.getManagementApplicationContext().get().getBean(WebFluxEndpointHandlerMapping.class);
7575
mappingInfoHandlerMethodMap.putAll(webFluxEndpointHandlerMapping.getHandlerMethods());
7676

7777
ControllerEndpointHandlerMapping controllerEndpointHandlerMapping = applicationContext.getBeansOfType(ControllerEndpointHandlerMapping.class).values().stream().findFirst().orElse(null);
7878
if (controllerEndpointHandlerMapping == null)
79-
controllerEndpointHandlerMapping = managementApplicationContext.getBean(ControllerEndpointHandlerMapping.class);
79+
controllerEndpointHandlerMapping = springDocWebServerContext.getManagementApplicationContext().get().getBean(ControllerEndpointHandlerMapping.class);
8080
mappingInfoHandlerMethodMap.putAll(controllerEndpointHandlerMapping.getHandlerMethods());
8181

8282
return mappingInfoHandlerMethodMap;

0 commit comments

Comments
 (0)