最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

一文詳解SpringBoot如何同時監(jiān)聽多個端口

 更新時間:2025年10月21日 08:19:29   作者:風象南  
這篇文章主要為大家詳細介紹了SpringBoot如何同時監(jiān)聽多個端口,文中的示例代碼講解詳細,具有一定的借鑒價值,感興趣的小伙伴可以了解下

前言

在日常開發(fā)中,我們通常構(gòu)建的 Spring Boot 應用都是"單面"的——一個端口,一套服務(wù)邏輯。但在某些實際場景中,我們可能需要一個應用能夠"一心二用":同時提供兩套完全不同的服務(wù),分別在不同的端口上運行。

比如:

  • 一個端口面向外部用戶,提供 API 服務(wù)
  • 另一個端口面向內(nèi)部管理,提供監(jiān)控和運維功能
  • 或者在一個應用中同時集成管理后臺和用戶前臺

場景示例

假設(shè)我們要開發(fā)一個電商平臺,需要同時滿足:

用戶端服務(wù)(端口8082)

  • 商品瀏覽
  • 購物車管理
  • 訂單處理

管理端服務(wù)(端口8083)

  • 商品管理
  • 訂單管理
  • 數(shù)據(jù)統(tǒng)計

這兩套服務(wù)功能完全不同,但需要部署在同一個應用中。

技術(shù)實現(xiàn)方案

方案一:多 Tomcat Connector 配置

最直接的方式是配置多個 Tomcat Connector。

1. 創(chuàng)建基礎(chǔ)項目結(jié)構(gòu)

// 主應用類
@SpringBootApplication
public class DualPortApplication {
    public static void main(String[] args) {
        SpringApplication.run(DualPortApplication.class, args);
    }
}

2. 配置雙端口

@Configuration
public class DualPortConfiguration {

    @Bean
    public ServletWebServerFactory servletContainer() {
        TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();

        // 添加第一個連接器(用戶端)
        factory.addAdditionalTomcatConnectors(createUserPortConnector());
        // 添加第二個連接器(管理端)
        factory.addAdditionalTomcatConnectors(createAdminPortConnector());

        return factory;
    }

    private Connector createUserPortConnector() {
        Connector connector = new Connector(TomcatServletWebServerFactory.DEFAULT_PROTOCOL);
        connector.setPort(8080);
        connector.setProperty("connectionTimeout", "20000");
        return connector;
    }

    private Connector createAdminPortConnector() {
        Connector connector = new Connector(TomcatServletWebServerFactory.DEFAULT_PROTOCOL);
        connector.setPort(8081);
        connector.setProperty("connectionTimeout", "20000");
        return connector;
    }
}

3. 路由分離策略

現(xiàn)在我們需要為不同端口提供不同的路由處理:

@Component
public class PortBasedFilter implements Filter {

    private static final String USER_PORT_HEADER = "X-User-Port";
    private static final String ADMIN_PORT_HEADER = "X-Admin-Port";

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {

        HttpServletRequest httpRequest = (HttpServletRequest) request;
        int port = httpRequest.getLocalPort();

        if (port == 8082) {
            // 用戶端請求
            httpRequest.setAttribute("serviceType", "USER");
        } else if (port == 8083) {
            // 管理端請求
            httpRequest.setAttribute("serviceType", "ADMIN");
        }

        chain.doFilter(request, response);
    }
}

4. 創(chuàng)建分離的 Controller

// 用戶端 Controller
@RestController
@RequestMapping("/api/user")
public class UserController {

    @GetMapping("/products")
    public String getProducts() {
        return "User Products API";
    }

    @PostMapping("/cart")
    public String addToCart() {
        return "Add to cart";
    }
}

// 管理端 Controller
@RestController
@RequestMapping("/api/admin")
public class AdminController {

    @GetMapping("/products")
    public String manageProducts() {
        return "Admin Products Management";
    }

    @GetMapping("/statistics")
    public String getStatistics() {
        return "Admin Statistics";
    }
}

方案二:基于路徑前綴的更優(yōu)雅方案

上述方案雖然可行,但在實際使用中可能會有一些問題。讓我們采用更優(yōu)雅的方案。

1. 自定義 Web MVC 配置

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
        // 為用戶端配置前綴
        configurer.addPathPrefix("/user", cls -> cls.isAnnotationPresent(UserApi.class));
        // 為管理端配置前綴
        configurer.addPathPrefix("/admin", cls -> cls.isAnnotationPresent(AdminApi.class));
    }
}

// 定義注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface UserApi {}

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface AdminApi {}

2. 使用注解標記 Controller

@RestController
@RequestMapping("/products")
@UserApi
public class UserProductController {

    @GetMapping
    public String getProducts() {
        return "用戶端商品列表";
    }

    @GetMapping("/{id}")
    public String getProduct(@PathVariable String id) {
        return "商品詳情: " + id;
    }
}

@RestController
@RequestMapping("/products")
@AdminApi
public class AdminProductController {

    @GetMapping
    public String getAllProducts() {
        return "管理端商品管理列表";
    }

    @PostMapping
    public String createProduct() {
        return "創(chuàng)建商品";
    }

    @PutMapping("/{id}")
    public String updateProduct(@PathVariable String id) {
        return "更新商品: " + id;
    }
}

高級特性實現(xiàn)

1. 端口感知的攔截器

@Component
public class PortAwareInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
                           Object handler) throws Exception {
        int port = request.getLocalPort();

        if (port == 8082) {
            // 用戶端邏輯
            validateUserRequest(request);
        } else if (port == 8083) {
            // 管理端邏輯
            validateAdminRequest(request);
        }

        return true;
    }

    private void validateUserRequest(HttpServletRequest request) {
        // 用戶端請求驗證邏輯
        String userAgent = request.getHeader("User-Agent");
        if (userAgent == null) {
            throw new SecurityException("Invalid user request");
        }
    }

    private void validateAdminRequest(HttpServletRequest request) {
        // 管理端請求驗證邏輯
        String authHeader = request.getHeader("Authorization");
        if (authHeader == null || !authHeader.startsWith("Bearer ")) {
            throw new SecurityException("Admin authentication required");
        }
    }
}

2. 端口特定的異常處理

@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(Exception.class)
    public ResponseEntity<ErrorResponse> handleException(
            Exception e, HttpServletRequest request) {

        int port = request.getLocalPort();
        ErrorResponse error = new ErrorResponse();

        if (port == 8082) {
            error.setCode("USER_ERROR_" + e.hashCode());
            error.setMessage("用戶服務(wù)異常: " + e.getMessage());
        } else if (port == 8083) {
            error.setCode("ADMIN_ERROR_" + e.hashCode());
            error.setMessage("管理服務(wù)異常: " + e.getMessage());
        }

        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                .body(error);
    }
}

3. 動態(tài)端口配置

@Configuration
@ConfigurationProperties(prefix = "dual.port")
@Data
public class DualPortProperties {
    private int userPort = 8082;
    private int adminPort = 8083;

    @Bean
    public ServletWebServerFactory servletContainer(DualPortProperties properties) {
        TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();

        factory.addAdditionalTomcatConnectors(
            createConnector("user", properties.getUserPort()));
        factory.addAdditionalTomcatConnectors(
            createConnector("admin", properties.getAdminPort()));

        return factory;
    }

    private Connector createConnector(String name, int port) {
        Connector connector = new Connector(TomcatServletWebServerFactory.DEFAULT_PROTOCOL);
        connector.setPort(port);
        connector.setName(name + "-connector");
        return connector;
    }
}

監(jiān)控和日志

1. 分端口日志記錄

@Configuration
public class LoggingConfiguration {

    @Bean
    public Logger userLogger() {
        return LoggerFactory.getLogger("USER-PORT");
    }

    @Bean
    public Logger adminLogger() {
        return LoggerFactory.getLogger("ADMIN-PORT");
    }
}

@Component
public class PortAwareLogger {

    private final Logger userLogger;
    private final Logger adminLogger;

    public PortAwareLogger(Logger userLogger, Logger adminLogger) {
        this.userLogger = userLogger;
        this.adminLogger = adminLogger;
    }

    public void logRequest(HttpServletRequest request) {
        int port = request.getLocalPort();
        String uri = request.getRequestURI();
        String method = request.getMethod();

        if (port == 8082) {
            userLogger.info("用戶端請求: {} {}", method, uri);
        } else if (port == 8083) {
            adminLogger.info("管理端請求: {} {}", method, uri);
        }
    }
}

2. 端口特定的健康檢查

@Component
public class DualPortHealthIndicator implements HealthIndicator {

    @Override
    public Health health() {
        return Health.up()
                .withDetail("user-port", 8082)
                .withDetail("admin-port", 8083)
                .withDetail("status", "Both ports are active")
                .build();
    }
}

@RestController
@RequestMapping("/health")
public class HealthController {

    @GetMapping("/user")
    public Map<String, Object> userHealth() {
        Map<String, Object> health = new HashMap<>();
        health.put("port", 8082);
        health.put("status", "UP");
        health.put("service", "user-api");
        return health;
    }

    @GetMapping("/admin")
    public Map<String, Object> adminHealth() {
        Map<String, Object> health = new HashMap<>();
        health.put("port", 8083);
        health.put("status", "UP");
        health.put("service", "admin-api");
        return health;
    }
}

安全考慮

端口訪問控制

@Configuration
@EnableWebSecurity
public class SecurityConfiguration {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(authz -> authz
                .requestMatchers(req -> req.getLocalPort() == 8082)
                    .permitAll()
                .requestMatchers(req -> req.getLocalPort() == 8083)
                    .hasRole("ADMIN")
                .anyRequest().denyAll()
            )
            .formLogin(form -> form
                .loginPage("/admin/login")
                .permitAll()
            );

        return http.build();
    }
}

總結(jié)

構(gòu)建"雙面" Spring Boot 應用是一個有趣且實用的技術(shù)挑戰(zhàn)。通過本文介紹的多種實現(xiàn)方案,我們可以根據(jù)實際需求選擇最適合的方式:

多 Connector 方案:適合簡單場景,實現(xiàn)直接

路徑前綴方案:適合需要清晰 API 結(jié)構(gòu)的場景

在某些特定場景下確實能夠簡化系統(tǒng)架構(gòu),降低運維成本。但同時也要注意避免過度復雜化,確保系統(tǒng)的可維護性和可擴展性。

到此這篇關(guān)于一文詳解SpringBoot如何同時監(jiān)聽多個端口的文章就介紹到這了,更多相關(guān)SpringBoot監(jiān)聽多個端口內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論

禹州市| 厦门市| 柞水县| 板桥市| 新兴县| 科技| 禄劝| 夏邑县| 敦煌市| 盈江县| 华池县| 双柏县| 拜泉县| 衡阳县| 高州市| 达日县| 额尔古纳市| 汶上县| 舞阳县| 沁水县| 永修县| 泰和县| 密山市| 呼图壁县| 丰都县| 兴仁县| 乐平市| 横峰县| 通化市| 佛冈县| 馆陶县| 神木县| 北流市| 通道| 绵竹市| 乌拉特后旗| 古蔺县| 明星| 青岛市| 潞西市| 白水县|