当前位置: 首页 > 知识库问答 >
问题:

在具有不同控制器的多个端口上运行SpingBoot应用程序

越麒
2023-03-14

我目前正在Spring Boot 2.4.0中编写一个应用程序,它需要侦听多个端口(具体来说是3个-但将来可能是4个)。这个想法是每个端口都提供不同的API供其他服务/应用程序连接到它。

所以,对于一个最小的工作示例,我会说我们有一个像这样的SpringBootApp:

@SpringBootApplication
public class MultiportSpringBoot {

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

现在,我想让它在3个不同的端口上监听,比如8080、8081和8082。所有人(!)对其中一个端口的请求,应由特定控制器“负责”。这一要求的原因之一是,一个控制器需要处理(常规)web前端,另一个控制器需要处理API。如果收到无效请求,API控制器需要给出与前端不同的错误消息。因此,给出的要求是明确的分离。

所以我想象不同端口的多个控制器,例如:

@Controller
public class Controller8080
{
    @RequestMapping(value = "/", method = RequestMethod.GET)
    public ModelAndView test8080()
    {
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("test8080");
        return modelAndView;
    }
}

其他端口具有类似控制器:

@Controller
public class Controller8081
{
    @RequestMapping(value = "/", method = RequestMethod.GET)
    public ResponseEntity test8081()
    {
        JSONObject stuff = doSomeStuffForPort8081();

        return new ResponseEntity<String>(stuff, HttpStatus.OK);
    }
}

我希望类似于@RequestMapping的注释能够匹配和修复控制器的端口号,但这似乎不是一个选项,因为似乎不存在这样的注释。

现在,这个主题似乎有点具体,这可能就是为什么你在网上找不到太多信息的原因。我发现在两个端口中启动Spring boot REST控制器,但我也只能运行一个实例。我看着https://tech.asimio.net/2016/12/15/Configuring-Tomcat-to-Listen-on-Multiple-ports-using-Spring-Boot.html,但这对于Spring Boot 2.4.0来说已经过时了,而且JavaMelody示例有点过多。

任何人都可以提供一个最小的工作示例来解决这个问题?

--

编辑:

再澄清一点:我需要多个独立的RESTController,每个控制器处理不同端口上的请求。一、 e.对域的请求。com:8080应该由不同于对域的请求的控制器处理。com:8081。

例如,考虑以下两个控制器,它们应该分别处理端口8080和8081上的请求:

//controller for port 8080
@RestController
public class ControllerA
{
    @GetMapping("/")
    String helloA(HttpServletRequest request)
    {
        return "ControllerA at port " + request.getLocalPort();
    }
}

//controller for port 8081
@RestController
public class ControllerB
{
    @GetMapping("/")
    String helloB(HttpServletRequest request)
    {
        return "ControllerB at port " + request.getLocalPort();
    }
}

共有3个答案

卞安邦
2023-03-14

另一种方法是使用org.springframework.web.servlet.mvc.condition.Request estCon条件,我认为这更干净https://stackoverflow.com/a/69397870/6166627

齐雅畅
2023-03-14

Özkan已经提供了关于如何通过提供基于TomcatServletWebServerFactory的您自己的ServletWebServerFactory@Bean来让Tomcat侦听多个端口的详细信息。

至于映射,这种方法怎么样:

向您的控制器添加@Request estMap(“/8080”)(方法保留其特定的@Request estMap)

@Controller
@RequestMapping("/8080")
public class Controller8080
{
    @RequestMapping(value = "/", method = RequestMethod.GET)
    public ModelAndView test8080()
    {
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("test8080");
        return modelAndView;
    }
}

将您自己的RequestMappingHandlerMapping定义为

public class PortBasedRequestMappingHandlerMapping extends RequestMappingHandlerMapping {

    @Override
    protected HandlerMethod lookupHandlerMethod(final String lookupPath, final HttpServletRequest request) throws Exception {
        return super.lookupHandlerMethod(request.getLocalPort() + lookupPath, request);
    }
}

并使用它

@Bean
public WebMvcRegistrations webMvcRegistrationsHandlerMapping() {
    return new WebMvcRegistrations() {

        @Override
        public RequestMappingHandlerMapping getRequestMappingHandlerMapping() {
            return new PortBasedRequestMappingHandlerMapping();
        }
    };
}

这将尝试将请求映射到端口8080上的 /foobar /8080/foobar.

逄征
2023-03-14

tomcat类名有一点变化,所以您提供的链接使用了旧代码,但对于新代码来说已经足够了。下面的代码显示了如何在spring boot 2.4中打开多个端口

@Bean
    public ServletWebServerFactory servletContainer() {
        TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
        tomcat.addAdditionalTomcatConnectors(additionalConnector());
        return tomcat;
    }

private Connector[] additionalConnector() {
    if (!StringUtils.hasLength(this.additionalPorts)) {
        return null;
    }
    String[] ports = this.additionalPorts.split(",");
    List<Connector> result = new ArrayList<>();
    for (String port : ports) {
        Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
        connector.setScheme("http");
        connector.setPort(Integer.valueOf(port));
        result.add(connector);
    }
    return result.toArray(new Connector[]{});
} 

为了用不同的控制器响应不同的端口,您可以实现诸如check-getLocalPort之类的逻辑,并相应地响应它。

@GetMapping("/hello")
String hello(HttpServletRequest request) {
    return "hello from " + request.getLocalPort();
}

或者,您可以在过滤器中编写逻辑控制器。下面的示例代码

 @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain fc) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse res = (HttpServletResponse) response;
        if (req.getLocalPort() == 8882 && req.getRequestURI().startsWith("/somefunction")) {
            res.sendError(HttpServletResponse.SC_FORBIDDEN);
        } else {
            fc.doFilter(request, response);
        }
    }

您可以在此处找到所有运行示例https://github.com/ozkanpakdil/spring-examples/tree/master/multiport

为了在不同的控制器上有相同的路径,你可以在类的顶部使用@Request estMap(“/控制器NO”)(检查),NO应该是数字1、2,否则Spring会抱怨“你有相同的路径”并给你这个异常

Caused by: java.lang.IllegalStateException: Ambiguous mapping. Cannot map 'testController2' method 
com.mascix.multiport.TestController2#hello(HttpServletRequest)
to {GET [/hello]}: There is already 'testController1' bean method

因为从设计开始,spring只允许一条路径对应一个控制器,在requestmapping之后,您可以这样更改过滤器。反射的好处是,你会学到非常不同的例外情况。Java语言lang.NoSuchMethodException或java。lang.IllegalArgumentException

我必须说,这种方法是不对的,并且与spring的设计背道而驰,为了让不同的端口具有不同的控制器,需要多个JVM。如果你把逻辑混为一谈,你将更难解决未来的问题和实现新的功能。

如果必须在一个jvm中执行此操作,请编写一个服务层,并从一个控制器中分别调用函数,然后编写如下逻辑

@GetMapping("/hello")
    String hello(HttpServletRequest request) {
        if (request.getLocalPort() == 8888) {
            return service.hellofrom8888();
        }
        if (request.getLocalPort() == 8889) {
            return service.hellofrom8889();
        }

        return "no repsonse ";
    }

至少这将易于维护和调试。但看起来仍然“丑陋”:

 类似资料:
  • 问题内容: 我有多个Node应用程序(在Express框架上构建)。 现在,我将它们这样放置- 现在,我想在同一端口(例如8080)上运行这3个应用程序。那可能吗 ? 需要注意的一件事是,每个应用都有类似的通用路线- 基本上,我想这样做,就像您可以使用Apache / PHP设置一样。 因此,当您拥有LAMP堆栈时- 您可以通过-作为其他应用轻松访问它们- 问题答案: 您可以使用:

  • 这是我的节点文件 我在上有HTML 和上的节点应用程序 我也转发了3000端口到80; 我想在这个服务器上的一个不同的端口上运行多个应用程序。 我应该为其他应用程序配置什么。

  • 在我的应用程序中有两个不同的阶段,它们是使用相同FXML文件的帮助屏幕。而不是创建两个FXML文件,我想只使用一个,并有两个控制器调用相同的fxml。 唯一的问题是控制器是在FXML文件中分配的。那么,有没有一种方法可以通过控制器类本身中的代码来更改指定的控制器? 我真的希望避免复制一个FXML文件,只是为了更改每个文件中的控制器。提前谢谢。

  • 我想部署一个tomcat服务器,以便它同时侦听两个端口(都用于超文本传输协议)。 为了确保您正确理解这个需求,我们只有一个服务器实例,但希望侦听HTTP协议的两个端口。例如,任何人都可以使用端口号7080和8080访问部署在我的服务器中的应用程序 有可能做到吗?如果可能,我们如何实现这一点?

  • 我有三个tomcat容器运行在不同的网桥网络与不同的子网和网关例如: 这些容器在不同的端口上运行,如8081, 8082, 8083 有没有办法在同一个8081中运行所有三个容器?如果可能的话,我怎么能在docker做呢。

  • 这个动作被一个LoginController映射,成功登录后,用户回到相同的,但作为登录用户,并用欢迎消息迎接用户。 index.htm还有另一个名为itemform的表单,它允许用户将项目名称作为文本添加。此操作由itemController控制。 我的问题是我的LoginController和itemController都有相同的请求映射,因此我得到了这个错误: 创建名为“org”的bean时