Spring Boot:将另一个端口上的请求发送到自定义 Servlet

Posted

技术标签:

【中文标题】Spring Boot:将另一个端口上的请求发送到自定义 Servlet【英文标题】:Spring Boot: Send requests on another port to a custom Servlet 【发布时间】:2015-06-27 18:01:47 【问题描述】:

我希望我的 spring-boot 应用程序在第二个端口上侦听(其中“第一个”端口是用于 spring-webmvc 端点的 server.port)并将所有进入第二个端口上的“/”的流量引导到一个我写的 Servlet 的实现。这些请求将是我希望与正常服务流量分开的 json-rpc 请求。我怎样才能做到这一点?

我找到了通过添加另一个连接器让嵌入式 Tomcat 在另一个端口上侦听的代码,如下所示:

@Bean
public EmbeddedServletContainerFactory servletContainer() 
    TomcatEmbeddedServletContainerFactory tomcat = new TomcatEmbeddedServletContainerFactory();
    tomcat.addAdditionalTomcatConnectors(createRpcServerConnector());

    return tomcat;


private Connector createRpcServerConnector() 
    Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
    Http11NioProtocol protocol = (Http11NioProtocol) connector.getProtocolHandler();
    connector.setPort(Integer.parseInt(env.getProperty("rpc.port")));

    return connector;

我发现你可以通过将另一个 Servlet 公开为 Bean 来注册另一个 Servlet,就像这样

@Bean
public Servlet rpcServlet() 
    return new RpcServlet();

但是,当像这样公开 Servlet 时,它只是将其映射到常规 server.port 上的 URL 模式。我无法弄清楚如何将它连接到 RPC 连接器,这样我的 webmvc 端口上的“/”不会尝试处理 RPC 请求,并且 RPC 端口不会将请求转发到我的 @RestController 方法。

也许这是我对Tomcat的误解。我什至应该为此使用Tomcat吗?我应该切换到 spring-boot 提供的另一个嵌入式 servlet 容器吗?

【问题讨论】:

我很好奇,为什么你在一个应用程序中运行这两个而不是两个单独的应用程序? 这是个好问题,蒂姆。不幸的是,这不是我的决定。我的任务是以这种方式实现它。我认为动机是出于我无法理解的原因将不同类型的流量放在不同的端口上。 没有两个独立的应用程序的动机是什么,每个应用程序都在一个端口上侦听?正如@Tim 所问,为什么它必须在一个应用程序中? 我相信其目的是提供两种不同的方式与同一个应用程序进行交互。 RPC 服务和 REST 端点都将管理相同类型的数据并使用相同的业务逻辑。 【参考方案1】:

要隔离Connector 以供单个应用程序使用,该连接器需要与其自己的Service 相关联,然后您需要将应用程序的Context 与该Service 相关联。

您可以通过将自己的 TomcatEmbeddedServletContainerFactory 子类作为 @Bean 并覆盖 getEmbeddedServletContainer(Tomcat tomcat) 来在 Spring Boot 应用程序中进行设置。这使您有机会进行所需的配置更改:

@Bean
public TomcatEmbeddedServletContainerFactory tomcatFactory() 
    return new TomcatEmbeddedServletContainerFactory() 

        @Override
        protected TomcatEmbeddedServletContainer getTomcatEmbeddedServletContainer(
                Tomcat tomcat) 
            Server server = tomcat.getServer();

            Service service = new StandardService();
            service.setName("other-port-service");
            Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
            connector.setPort(8081);
            service.addConnector(connector);
            server.addService(service);             

            Engine engine = new StandardEngine();
            service.setContainer(engine);

            Host host = new StandardHost();
            host.setName("other-port-host");
            engine.addChild(host);
            engine.setDefaultHost(host.getName());

            Context context = new StandardContext();
            context.addLifecycleListener(new FixContextListener());
            context.setName("other-port-context");
            context.setPath("");
            host.addChild(context);

            Wrapper wrapper = context.createWrapper();
            wrapper.setServlet(new MyServlet());
            wrapper.setName("other-port-servlet");
            context.addChild(wrapper);
            context.addServletMapping("/", wrapper.getName());

            return super.getTomcatEmbeddedServletContainer(tomcat);
        
    ;


private static class MyServlet extends HttpServlet 

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException 
        resp.getWriter().println("Hello, world");
    


将此 bean 添加到您的应用程序后,http://localhost:8081 应由MyServlet 处理并返回包含“Hello, world”的响应。

【讨论】:

我将补充一点,为了让请求范围的 bean 在此 servlet 处理的请求中正常工作,请将 RequestContextListener 添加到上下文中,如下所示: context.addApplicationEventListener(new RequestContextListener());

以上是关于Spring Boot:将另一个端口上的请求发送到自定义 Servlet的主要内容,如果未能解决你的问题,请参考以下文章

在 Spring Boot 中创建 PROXY 服务,监听多个端口,并将 GET 请求重定向到新 URL

无法将http post请求发送到spring boot

如何从 nginx 发送请求并将容器反应到 Spring Boot 容器?

使用 Angular 2 和 Spring Boot 发送发布请求

使用 Spring Boot 从不同端口提供 REST API 和静态内容

如何使用 Postman 表单数据将 POST 请求发送到 Spring Boot REST API?