如何将Spring Actuator的/health端点单独发布到9999端口?
Hey there! Great question—separating the /health endpoint to a dedicated port while keeping other Actuator endpoints on the default management port is totally doable in Spring Boot. Let me walk you through two reliable approaches depending on your Spring Boot version and preferences:
Approach 1: Dedicated Web Server for /health (Clean, Recommended)
This method spins up a separate lightweight web server just for the /health endpoint, keeping it isolated from other Actuator endpoints. Works for Spring Boot 2.x and 3.x.
Step 1: Configure Application Properties
First, update your application.yml (or application.properties) to exclude /health from the default management server and set up your ports:
server: port: 8080 # Your main application port (adjust as needed) management: server: port: 8081 # Port for all Actuator endpoints EXCEPT /health endpoints: web: exposure: include: "*" exclude: "health" # Keep /health off the default management port endpoint: health: enabled: true # Ensure the health endpoint itself is active
Step 2: Add Configuration for the Dedicated Health Server
Create a configuration class to launch a separate web server on port 9999, and proxy the /health endpoint to it:
import org.springframework.boot.actuate.health.Health; import org.springframework.boot.actuate.health.HealthEndpoint; import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @Configuration public class HealthPortConfiguration { @Bean public AnnotationConfigServletWebServerApplicationContext healthServerContext(HealthEndpoint healthEndpoint) { // Create a standalone context for the 9999 port server AnnotationConfigServletWebServerApplicationContext context = new AnnotationConfigServletWebServerApplicationContext(); // Reuse the health endpoint bean from the main application context context.getBeanFactory().registerSingleton("healthEndpoint", healthEndpoint); // Register our proxy controller for the health endpoint context.register(HealthProxyConfig.class); // Set the server port to 9999 TomcatServletWebServerFactory serverFactory = new TomcatServletWebServerFactory(9999); context.setServletWebServerFactory(serverFactory); // Start the context context.refresh(); return context; } // Proxy controller that only responds on the 9999 port @RestController static class HealthProxyController { private final HealthEndpoint healthEndpoint; public HealthProxyController(HealthEndpoint healthEndpoint) { this.healthEndpoint = healthEndpoint; } @GetMapping("/actuator/health") public Health getHealth() { // Delegate to the actual health endpoint return healthEndpoint.health(); } } @Configuration static class HealthProxyConfig { @Bean public HealthProxyController healthProxyController(HealthEndpoint healthEndpoint) { return new HealthProxyController(healthEndpoint); } } }
What This Does:
8080: Main application, no Actuator endpoints exposed8081: All Actuator endpoints except/health9999: Only the/actuator/healthendpoint is accessible
Approach 2: Interceptor-Based Port Restriction
If you prefer not to spin up a separate server, you can use a request interceptor to block endpoints based on the incoming port. This works best for Spring Boot 2.x.
Step 1: Base Configuration
Start with this application.yml:
server: port: 8080 management: server: port: 8081 endpoints: web: exposure: include: "*"
Step 2: Add Interceptor and Extra Server
Create a configuration class to add a port-checking interceptor and launch the 9999 port server:
import org.springframework.boot.actuate.endpoint.web.annotation.ControllerEndpoints; import org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpoints; import org.springframework.boot.actuate.endpoint.web.servlet.WebMvcEndpointHandlerMapping; import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; import org.springframework.boot.web.servlet.server.ServletWebServerFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @Configuration public class ActuatorPortRestrictionConfig { @Bean public WebMvcEndpointHandlerMapping webMvcEndpointHandlerMapping( ServletEndpoints servletEndpoints, ControllerEndpoints controllerEndpoints, WebMvcEndpointHandlerMapping.WebMvcEndpointHandlerMappingConfiguration configuration) { WebMvcEndpointHandlerMapping mapping = new WebMvcEndpointHandlerMapping( servletEndpoints, controllerEndpoints, configuration.getPrefix(), configuration.getEndpointsByRequestPredicate(), configuration.getCorsConfiguration()); // Add interceptor to restrict endpoints by port mapping.setInterceptors(new HandlerInterceptor() { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String requestURI = request.getRequestURI(); int localPort = request.getLocalPort(); // Enforce rules: // 9999 port only allows /actuator/health if (localPort == 9999) { if (!requestURI.equals("/actuator/health")) { response.sendError(HttpServletResponse.SC_NOT_FOUND); return false; } } // 8081 port blocks /actuator/health else if (localPort == 8081 && requestURI.equals("/actuator/health")) { response.sendError(HttpServletResponse.SC_NOT_FOUND); return false; } return true; } }); return mapping; } // Launch the extra server on port 9999 @Bean public ServletWebServerFactory healthServerFactory() { return new TomcatServletWebServerFactory(9999); } }
What This Does:
- The interceptor checks the incoming port and blocks unauthorized endpoints
9999: Only/actuator/healthworks; other paths return 4048081: All Actuator endpoints work except/health8080: Main application, no Actuator endpoints
内容的提问来源于stack exchange,提问作者Always_Beginner

