[Spring Boot] 使用多个Servlet

本文介绍了如何在Spring Boot应用中配置Servlet、Filter和监听器。通过示例展示了使用ServletRegistrationBean注册DispatcherServlet及自定义Servlet的方法,并说明了如何利用@ServletComponentScan自动注册组件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

当使用Spring boot的嵌入式servlet容器时,可以通过Spring bean或扫描Servlet组件的方式注册Servlet、Filter和Servlet规范的所有监听器(例如HttpSessionListener)

  • 当urlMapping不是很复杂时,可以通过ServletRegistrationBeanFilterRegistrationBean 和 ServletListenerRegistrationBean获得完整控制。如果bean实现了ServletContextInitializer接口的话则可以直接注册。
  • 当使用@ServletComponentScan扫描Servlet组件时,Servlet、过滤器和监听器可以是通过@WebServlet@WebFilter@WebListener自动注册
Application.java

 

package com.yqu.multiservlet;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.embedded.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.web.servlet.DispatcherServlet;

@SpringBootApplication
public class Application {

  public static void main(String[] args) {
    SpringApplication.run(Application.class, args);
  }

  @Bean
  public ServletRegistrationBean dispatcherRegistration(
      DispatcherServlet dispatcherServlet) {
    ServletRegistrationBean registration =
        new ServletRegistrationBean(dispatcherServlet);
    registration.addUrlMappings("/hirest/*");
    printStacks();
    return registration;
  }

  @Bean
  public ServletRegistrationBean servletRegistrationBean() {
    printStacks();
    return new ServletRegistrationBean(
        new SigninServlet(), "/signin");
  }

  private void printStacks() {
    StackTraceElement[] elements = Thread.currentThread().getStackTrace();
    System.out.println("========================");

    for (int i = 0; i < elements.length; i++) {
      System.out.println(elements[i]);
    }
  }
}
SigninServlet.java
package com.yqu.multiservlet;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class SigninServlet extends HttpServlet {
  public void init(ServletConfig config)
      throws ServletException {
    super.init(config);

  }

  protected void doGet(
      HttpServletRequest request,
      HttpServletResponse response)
      throws ServletException, IOException {
    response.sendRedirect("http://blog.sina.com.cn/yandongqu");
  }
}
HelloController.java
package com.yqu.multiservlet;

import org.springframework.hateoas.ResourceSupport;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo;
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn;

@RestController
public class HelloController {
  @RequestMapping(value = "/", method = RequestMethod.GET)
  @ResponseBody
  public HttpEntity  home() {
    ResourceSupport home = new ResourceSupport();
    home.add(linkTo(methodOn(HelloController.class).home()).withSelfRel());
    return new ResponseEntity(home, HttpStatus.OK);
  }
}
application.properties
server.context-path=/HelloMultiServlet
server.port=8080

applicationDefaultJvmArgs: [
    "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=55558"
]
build.gradle
buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:1.2.6.RELEASE")
    }
}

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'spring-boot'

jar {
    baseName = 'hello-multiservlet'
    version =  '0.1.0'
}

repositories {
    mavenCentral()
}

sourceCompatibility = 1.8
targetCompatibility = 1.8

dependencies {
    compile("org.springframework.boot:spring-boot-starter-actuator")
    compile("org.springframework.boot:spring-boot-starter-web")
    compile("com.fasterxml.jackson.core:jackson-databind")
    compile("org.springframework.hateoas:spring-hateoas")
    compile("org.springframework.plugin:spring-plugin-core:1.1.0.RELEASE")
    compile("com.jayway.jsonpath:json-path:0.9.1")
}

task wrapper(type: Wrapper) {
    gradleVersion = '2.3'
}

测试

  • 通过REST访问http://localhost:8080/HelloMultiServlet/hirest/

 

<think>我们正在处理一个关于在Spring Boot应用中配置多个Servlet端口的问题。据引用内容,我们注意到在配置Turbine时提到了管理端口的设置,但这并不是直接关于多端口配置的。然而,我们可以从引用中提取一些有用的信息:管理端口可以通过`management.server.port`进行设置,并且可以独立于主服务器端口。 在Spring Boot中,默认情况下,应用运行在一个单独的端口上(由`server.port`配置)。但是,有时我们可能需要同时监听两个不同的端口,例如一个用于主应用,另一个用于管理端点或不同的服务。 实际上,Spring Boot本身并不直接支持单个应用实例监听多个端口(除了管理端口可以通过`management.server.port`设置,用于暴露执行器端点)。但是,我们可以通过编程方式配置额外的连接器来实现。 以下是两种主要方法: 方法1:使用管理端口(仅适用于执行器端点) 如果你只是想将管理端点(如健康检查、指标等)放在不同的端口上,那么可以使用Spring Boot执行器的管理端口特性。在`application.properties`中配置: ```properties server.port=8080 management.server.port=8081 ``` 这样,主应用在8080端口,而执行器端点则在8081端口(例如,访问`http://localhost:8081/actuator/health`)。 方法2:配置多个连接器(适用于任意Servlet内容) 如果你希望在不同的端口上提供完全不同的服务(不仅仅是执行器端点),那么你需要自定义内嵌的Servlet容器(如Tomcat、Jetty或Undertow),添加额外的连接器。 以下以Tomcat为例,展示如何配置多个端口: 步骤1:创建一个配置类,注册一个`TomcatServletWebServerFactory` bean,并添加一个额外的连接器。 步骤2:为不同的端口配置不同的调度器(DispatcherServlet)或Servlet上下文。 但是,请注意:默认情况下,Spring Boot使用一个`DispatcherServlet`作为主Servlet。如果我们想要在另一个端口上提供不同的服务,我们可能需要定义一个新的`DispatcherServlet`(或者自定义的Servlet)并将其映射到该端口的上下文中。 由于这个需求相对复杂,下面提供一个示例,展示如何配置Tomcat以监听两个端口,并在第二个端口上提供一组不同的端点(例如一个独立的REST服务)。 示例:配置两个端口(8080和8081),其中8080是主应用,8081是另一个端口,提供另一个DispatcherServlet的上下文。 1. 创建第二个调度器(DispatcherServlet)的配置: ```java @Configuration public class SecondaryDispatcherServletConfig { @Bean public DispatcherServlet secondaryDispatcherServlet() { return new DispatcherServlet(); } // 注意:我们需要为第二个DispatcherServlet创建一个新的WebApplicationContext(子上下文) @Bean public ServletRegistrationBean<DispatcherServlet> secondaryServletRegistration() { ServletRegistrationBean<DispatcherServlet> registration = new ServletRegistrationBean<>( secondaryDispatcherServlet(), "/secondary/*"); registration.setName("secondary"); registration.setLoadOnStartup(1); // 注意:这里不能设置上下文,因为我们需要在下面的工厂中为第二个端口设置独立的上下文 return registration; } } ``` 2. 创建Tomcat工厂配置,添加第二个连接器,并为第二个端口创建独立的上下文: ```java import org.apache.catalina.connector.Connector; import org.apache.catalina.Context; import org.apache.catalina.Wrapper; import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; import org.springframework.boot.web.embedded.tomcat.TomcatWebServer; 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.DispatcherServlet; @Configuration public class WebServerConfig { @Bean public ServletWebServerFactory servletContainer() { TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory() { @Override protected TomcatWebServer getTomcatWebServer(org.apache.catalina.startup.Tomcat tomcat) { // 在创建主服务器后,再添加一个连接器(第二个端口) tomcat.getService().addConnector(createSecondaryConnector()); return super.getTomcatWebServer(tomcat); } @Override protected void postProcessContext(Context context) { // 主端口的上下文,不需要在这里处理 } }; // 添加额外的定制:为第二个端口创建上下文 tomcat.addAdditionalTomcatContexts(createSecondaryContext()); return tomcat; } private Connector createSecondaryConnector() { Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol"); connector.setPort(8081); return connector; } private Context createSecondaryContext() { // 创建第二个端口的上下文 Context context = new org.apache.catalina.core.StandardContext(); context.setPath(""); context.setDocBase(null); context.addLifecycleListener(new org.apache.catalina.startup.ContextConfig()); // 添加第二个DispatcherServlet到该上下文 Wrapper wrapper = context.createWrapper(); wrapper.setName("secondary"); wrapper.setServlet(secondaryDispatcherServlet()); // 这里需要获取到我们定义的第二个DispatcherServlet wrapper.setLoadOnStartup(1); context.addChild(wrapper); context.addServletMappingDecoded("/", "secondary"); // 注意:这里需要确保上下文有必要的监听器和配置,否则会启动失败 context.addApplicationListener("org.springframework.web.context.ContextLoaderListener"); context.addParameter("contextClass", "org.springframework.web.context.support.AnnotationConfigWebApplicationContext"); // 设置该上下文的配置类(独立于主配置) context.addParameter("contextConfigLocation", SecondaryConfig.class.getName()); return context; } // 注意:这里需要注入我们在另一个配置类中定义的secondaryDispatcherServlet @Bean public DispatcherServlet secondaryDispatcherServlet() { return new DispatcherServlet(); } } ``` 3. 创建第二个端口的配置类(独立于主配置): ```java @Configuration @ComponentScan(basePackages = "com.example.secondary") public class SecondaryConfig implements WebMvcConfigurer { // 这里配置第二个DispatcherServlet的MVC相关设置 } ``` 注意:上述示例比较复杂,需要确保第二个端口的上下文正确初始化,并且配置了正确的组件扫描包。此外,还需要注意避免与主端口的组件冲突。 由于这种配置的复杂性,通常建议使用微服务架构,将不同的服务拆分为独立的应用。如果必须在同一个应用中监听多个端口,请仔细测试。 另外,引用中提到的管理端口配置是一个更简单的方案,但它只适用于执行器端点。如果你只需要将管理端点放在另一个端口,那么使用管理端口配置是最简单的。 总结: - 如果只需要分离执行器端点,使用`management.server.port`。 - 如果需要在另一个端口提供完全不同的服务,则需要自定义内嵌容器并添加额外的连接器和上下文。 由于问题复杂度高,这里只提供了一种基于Tomcat的实现思路。实际应用中可能会遇到各种问题,需要据具体需求调整。 相关问题: 1. 如何在Spring Boot配置管理端口? 2. 如何为Spring Boot应用添加多个Tomcat连接器? 3. 如何在同一个Spring Boot应用中创建多个独立的DispatcherServlet? 4. 如何避免多个Spring上下文之间的冲突? 5. 在微服务架构中,如何设计多端口服务?</think>在 Spring Boot 应用中配置多个 Servlet 端口需要自定义内嵌容器配置。以下是两种主要实现方式: ### 方法 1:使用管理端口(推荐) 这是官方支持的方式,通过 `management.server.port` 配置独立的管理端口: ```properties # 主应用端口 server.port=8080 server.servlet.context-path=/app # 管理端口(独立) management.server.port=8081 management.server.servlet.context-path=/admin management.endpoints.web.exposure.include=* ``` - 主应用访问:`http://localhost:8080/app` - 管理端点访问:`http://localhost:8081/admin/actuator/health` ### 方法 2:自定义多个连接器(高级) 需要编程式配置内嵌容器,以 Tomcat 为例: ```java import org.apache.catalina.connector.Connector; import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class MultiPortConfig { @Bean public TomcatServletWebServerFactory servletContainer() { TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory(); // 添加额外连接器 (端口 8081) factory.addAdditionalTomcatConnectors(createConnector(8081, "/secondary")); return factory; } private Connector createConnector(int port, String contextPath) { Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol"); connector.setPort(port); connector.setProperty("contextPath", contextPath); return connector; } } ``` ### 关键说明 1. **管理端口适用场景** - 执行器端点监控 - 健康检查接口 - 独立的管理后台 ```properties # 自定义管理端点路径 management.endpoints.web.base-path=/manage ``` 2. **多连接器注意事项** - 需要手动处理上下文隔离 - 不同端口的 session 不共享 - 适用于特殊场景如: ```java // 示例:8081 端口仅处理特定请求 @Bean public ServletRegistrationBean<CustomServlet> secondaryServlet() { return new ServletRegistrationBean<>(new CustomServlet(), "/api/v2/*"); } ``` 3. **端口冲突解决** ```java // 动态获取可用端口 connector.setPort(ServerSocket(0).getLocalPort()); ``` ### 配置验证 使用 `curl` 测试多端口配置: ```bash # 测试主端口 curl http://localhost:8080/app/home # 测试管理端口 curl http://localhost:8081/admin/actuator/info # 测试自定义连接器 curl http://localhost:8081/secondary/api/v2/data ``` ### 相关问题 1. 如何在 Spring Boot 中为管理端口配置独立的安全策略?[^1] 2. 如何让不同端口的 Servlet 共享 Spring 上下文?[^2] 3. Spring Boot 支持哪些内嵌容器的多端口配置?[^1] 4. 如何为不同端口的 Servlet 设置独立的访问日志?[^2] 5. 在多端口配置中如何处理 HTTPS 证书的绑定?[^1] [^1]: 基于 Spring Boot 官方文档的容器定制指南 [^2]: 参考 Tomcat 多连接器配置的最佳实践
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值