Tomcat Spring引导:在另一个端口上向自定义Servlet发送请求

Tomcat Spring引导:在另一个端口上向自定义Servlet发送请求,tomcat,servlets,spring-boot,Tomcat,Servlets,Spring Boot,我希望我的spring boot应用程序在第二个端口上侦听(其中“第一个”端口是用于spring webmvc端点的server.port),并将第二个端口上的“/”的所有通信量定向到我编写的Servlet实现。这些请求将是json rpc请求,我希望将其与正常服务流量分开。我怎样才能做到这一点 我已经找到了让嵌入式Tomcat通过添加另一个连接器在另一个端口上侦听的代码,如下所示: @Bean public EmbeddedServletContainerFactory servletCont

我希望我的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公开,就可以注册它,如下所示

@Bean
public Servlet rpcServlet() {
    return new RpcServlet();
}
但是,在公开这样的Servlet时,它只是将其映射到常规server.port上的URL模式。我无法确定如何将其连接到RPC连接器,以便webmvc端口上的“/”不尝试处理RPC请求,并且RPC端口不将请求转发到我的
@RestController
方法


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

要隔离一个
连接器
供单个应用程序使用,该连接器需要与其自身的
服务
相关联,然后您需要将应用程序的
上下文
与该
服务
相关联

您可以在Spring Boot应用程序中设置此设置,方法是提供自己的
TomcatEmbeddedServletContainerFactory
子类作为
@Bean
,并覆盖
getEmbeddedServletContainer(Tomcat-Tomcat)
。这使您有机会进行所需的配置更改:

@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添加到你的应用程序中时,应该由
MyServlet
处理,并返回一个包含“Hello,world”的响应。

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