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

时间:2015-04-20 20:18:37

标签: tomcat servlets spring-boot

我希望我的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;
}

我发现你可以简单地通过将它暴露为Bean来注册另一个Servlet,就像这样

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

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

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

1 个答案:

答案 0 :(得分:2)

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

您可以通过提供自己的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"的回复。