【问题标题】:How to host a SOAP service and REST service at the same port?如何在同一个端口托管 SOAP 服务和 REST 服务?
【发布时间】:2013-07-12 22:29:12
【问题描述】:

有谁知道如何配置它,以便 SOAP 服务和 REST 服务可以在应用程序服务器之外使用 Jersey (Grizzly) 共享同一个端口?

  • 我的肥皂服务位于 www.someurl.com:port/soap/crm
  • 我的休息服务在 www.someurl.com:port/crm

这些服务共享相同的端口但不同的基本 url,因此应该能够在该端口上并行运行。但是,有一个端口绑定错误..

所有这些都在自定义服务应用程序中,没有 web.xml 之类的。

REST 服务使用 Jersey,而 Soap 服务是一个发布在端点上的“ReceptionService”类。

URI soapUri = URI.create("192.168.0.0:1234\soap\Crm")
URI restUri = URI.create("192.168.0.0:1234\crm")

// START SOAP SERVICE
Object reception = getObjectResource(ReceptionService.class);
Endpoint e = Endpoint.publish(soapUri, reception);

// START REST SERVICE    
ResourceConfig rc = new ResourceConfig().packages("company.rest");
HttpServer server = GrizzlyHttpServerFactory.createHttpServer(restUri, rc);

当我尝试这个时,Grizzly 会吐出“java.net.BindException: Address already in use: bind”

我的肥皂服务接待是这样设置的:

    @WebService(targetNamespace = "company.crm")
    @SOAPBinding(style = SOAPBinding.Style.DOCUMENT, use = SOAPBinding.Use.LITERAL,      parameterStyle = SOAPBinding.ParameterStyle.WRAPPED)
    public class Reception implements ReceptionService {
     ... methods
    }

我的休息服务类像往常一样被注释...

@Path("hello/{username}")
public class Hello { ... }

我在这方面有点新手,任何指针都将不胜感激。请不要打扰建议我运行应用程序服务器。这不是这里的问题 - 问题是我如何解决端口绑定问题而不转移到其他一些 Web 服务框架?

注意赏金:我不能重复这个足够

“赏金获胜者将演示如何在同一端点上同时使用 Jersey for REST 和 Java SOAP 服务(带注释的 JAX-WS)。答案不需要更改 Rest 和 Soap 带注释的类。但是, 并且 HTTP 服务器代码更改或配置更改以使其工作是可以接受的。切换到 Jetty 或其他一些应用程序服务器是不可接受的该解决方案必须 100% 嵌入并使用 Java SE 和 Java Web 服务库运行。”

【问题讨论】:

  • 更多信息会有所帮助,例如您使用哪种类型的 Web 服务器/应用程序服务器? web.xml 长什么样子?
  • 您找到解决方案了吗?我也面临同样的问题
  • 不。我仍然将它们分开的端口。我将不得不做很多修改我的代码,我没有时间或耐心。希望以后可以配置。

标签: java rest soap endpoint


【解决方案1】:

这是我用来在单个端口(2 个不同的上下文路径)上托管 rest 和 soap 服务的大部分代码,完全嵌入到我的应用程序中(显然使用 Grizzly),并且配置了 spring...

package com.mycompany.structure.web.grizzly;

import java.io.IOException;
import java.lang.reflect.Constructor;
import java.net.BindException;
import java.util.EnumSet;
import java.util.LinkedList;
import javax.servlet.DispatcherType;
import javax.servlet.Servlet;
import com.mycompany.structure.web.jersey.jackson.JsonResourceConfig;
import com.mycompany.structure.web.jersey.spring.ExposedApplicationContext;
import org.glassfish.grizzly.http.server.HttpHandler;
import org.glassfish.grizzly.http.server.HttpServer;
import org.glassfish.grizzly.http.server.NetworkListener;
import org.glassfish.grizzly.jaxws.JaxwsHandler;
import org.glassfish.grizzly.servlet.WebappContext;
import org.glassfish.jersey.servlet.ServletContainer;
import org.smallmind.nutsnbolts.lang.web.PerApplicationContextFilter;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;

public class GrizzlyInitializingBean implements DisposableBean, ApplicationContextAware, ApplicationListener, BeanPostProcessor {

  private static final Class[] NO_ARG_SIGNATURE = new Class[0];
  private HttpServer httpServer;
  private LinkedList<WebService> serviceList = new LinkedList<>();
  private ServletInstaller[] servletInstallers;
  private String host;
  private String contextPath;
  private String restPath;
  private String soapPath;
  private int port;
  private boolean debug = false;

  public void setHost (String host) {

    this.host = host;
  }

  public void setPort (int port) {

    this.port = port;
  }

  public void setContextPath (String contextPath) {

    this.contextPath = contextPath;
  }

  public void setRestPath (String restPath) {

    this.restPath = restPath;
  }

  public void setSoapPath (String soapPath) {

    this.soapPath = soapPath;
  }

  public void setServletInstallers (ServletInstaller[] servletInstallers) {

    this.servletInstallers = servletInstallers;
  }

  public void setDebug (boolean debug) {

    this.debug = debug;
  }

  @Override
  public synchronized void onApplicationEvent (ApplicationEvent event) {

    if (event instanceof ContextRefreshedEvent) {

      if (debug) {
        System.setProperty("com.sun.xml.ws.transport.http.HttpAdapter.dump", "true");
      }
      httpServer = new HttpServer();
      httpServer.addListener(new NetworkListener("grizzly2", host, port));

      WebappContext webappContext = new WebappContext("Grizzly Application Context");
      webappContext.addServlet("JAX-RS Application", new ServletContainer(new JsonResourceConfig(ExposedApplicationContext.getApplicationContext()))).addMapping(restPath + "/*");
      webappContext.addFilter("per-application-data", new PerApplicationContextFilter()).addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), restPath + "/*");
      webappContext.addListener("org.springframework.web.context.request.RequestContextListener");

      for (ServletInstaller servletInstaller : servletInstallers) {
        try {

          Constructor<? extends Servlet> servletConstructor;
          Servlet servlet;
          String urlPattern;

          servletConstructor = servletInstaller.getServletClass().getConstructor(NO_ARG_SIGNATURE);
          servlet = servletConstructor.newInstance();

          webappContext.addServlet(servletInstaller.getDisplayName(), servlet).addMapping((urlPattern = servletInstaller.getUrlPattern()) == null ? "/" : urlPattern);
        }
        catch (Exception exception) {
          throw new GrizzlyInitializationException(exception);
        }
      }

      webappContext.deploy(httpServer);

      for (WebService webService : serviceList) {

        HttpHandler httpHandler = new JaxwsHandler(webService.getService(), false);

        httpServer.getServerConfiguration().addHttpHandler(httpHandler, soapPath + webService.getPath());
      }

      try {
        httpServer.start();
      }
      catch (IOException ioException) {
        if (!(ioException instanceof BindException)) {
          throw new GrizzlyInitializationException(ioException);
        }
      }
    }
  }

  @Override
  public void setApplicationContext (ApplicationContext applicationContext) {

    ExposedApplicationContext.register(applicationContext);
  }

  @Override
  public Object postProcessBeforeInitialization (Object bean, String beanName) throws BeansException {

    return bean;
  }

  @Override
  public Object postProcessAfterInitialization (Object bean, String beanName) throws BeansException {

    ServicePath servicePath;

    if ((servicePath = bean.getClass().getAnnotation(ServicePath.class)) != null) {
      serviceList.add(new WebService(servicePath.value(), bean));
    }

    return bean;
  }

  @Override
  public synchronized void destroy () {

    if (httpServer != null) {
      httpServer.shutdown();
    }
  }
}

【讨论】:

  • 太棒了。我去看看。
【解决方案2】:

Jetty 的覆盖功能允许您在同一个 Jetty 实例/端口上部署具有不同路径的两个不同 webapp。

您将拥有一个带有 Jersey servlet(用于 REST)的 web.xml,而另一个带有 SOAP servlet 的 web.xml。

http://www.eclipse.org/jetty/documentation/current/overlay-deployer.html

【讨论】:

  • 好的。如果我把它全部移到码头,那可能会奏效。而且由于我现在使用 Jetty 来处理 Restful 方面的事情,因为我喜欢它与 Guice 轻松配置的方式,那么也许 Soap 也可以这样做。
  • 但是,那一定是不涉及web.xml文件的解决方案。如果您可以展示如何使用 Jetty 而没有 xml 文件来执行此操作,那么我会认为这是一个正确的答案。
【解决方案3】:

不可能在同一个端口上启动多个服务。

当您希望您的应用程序可以通过同一端口访问时,您必须使用应用程序 服务器。

您必须注意服务器上的两个应用程序都可以通过不同的 URL (web.xml) 访问。

同一个应用服务器上的所有应用现在都可以通过同一个端口访问。

【讨论】:

  • 如果它可以通过应用服务器完成,那么它可以在没有应用服务器的情况下以编程方式完成。那么 Glassfish 如何使用 jersey(grizzly http)作为其余服务器和肥皂服务在同一端口上托管......这是百万美元的问题:)
【解决方案4】:

您所说的只是用于公开服务的两个不同接口,是的,您可以将它们托管在一个端口上,只需将其部署在同一个容器中,您就可以同时启动并运行两个接口。

只要确保您没有上下文路径冲突,上述问题中提到的 url 中似乎没有发生这种冲突。

例如让其余接口部署为:

www.someurl.com:port2/crm ,所以soap不应该部署在同一个url,www.someurl.com:port1/soap/crm ,没关系。

您还应该解释一下您是如何部署接口的,作为单独的war文件或在单个war文件中。

【讨论】:

  • 谢谢。但我需要他们共享相同的 URL 端口。没有 War 文件,没有应用服务器,只是像上面那样编码。它在单独的端口上工作正常,但在共享同一端口时会导致绑定异常(尽管端点实际上不同。)
  • 这里的问题是,Endpoint.publish 将启动并且 HTTP Server 和 Grizzly 部分也会启动一个 HTTP Server,因为你有一个端口冲突。
  • 那么如何让灰熊也提供肥皂服务呢? IE。并排正确发布接待服务?一定有办法,因为 Microsoft Server 和 Apache CMX 也允许相同的行为。
  • 我猜你最好的选择是在 web.xml 中为应用程序提供一个部署描述符,它将集成你提供的服务并将它们作为一个单元部署在一起。
  • 对不起,我没有在这个上下文中使用应用服务器。
【解决方案5】:

如果您为 Web 服务使用通用容器(例如 tomcat),那么您可以获得到达同一端口的两个服务的请求。您可以将基于 REST 和 SOAP 的服务部署为应用程序的一部分。容器将接受传入的请求,并根据应用程序上下文将它们转发给应用程序。在您的应用程序 web.xml 中,您可以根据请求 URL 映射配置发送请求的位置。

【讨论】:

  • 谢谢。我在客户服务器应用程序中使用 Jersey(在 Glassfish 之外)。我会在上面发布更多信息,也许有人有解决方案。
猜你喜欢
  • 2015-10-15
  • 1970-01-01
  • 1970-01-01
  • 2019-08-15
  • 1970-01-01
  • 2011-12-13
  • 1970-01-01
  • 2017-11-14
  • 1970-01-01
相关资源
最近更新 更多