如何通过编程将webservice发布到Tomcat

7

我想要以编程方式将一个webservice发布到Tomcat中。
例如使用JAX-WS或Apache CXF。
类似于Endpoint.publish(...)

//how to tell this tomcat?
Endpoint.publish("http://0.0.0.0:8080/SimpleService", serviceImpl);
//or better something like this:
Endpoint.publish("/SimpleService", serviceImpl);

不需要使用web.xml和/或sun-jaxws.xml(对于每个服务)。

问题:
是否已知有一种方法可以实现此目的(使用JAX-WS或Apache CXF或...)?

(我知道已经发布了类似的问题。 但是没有一个真正回答我的问题。)


我不确定您的要求。您想在Tomcat上部署一个应用程序(因此需要web.xml),该应用程序以编程方式发布新的端点以接收请求。是这样吗? - pedrofb
Tomcat管理器Web应用程序可用于部署新的Web应用程序(通过调用正确的URL)(https://tomcat.apache.org/tomcat-6.0-doc/manager-howto.html#Deploy_A_New_Application_from_a_Local_Path)。 - Maxx
1个回答

2
这是对我自己问题的回答。
在Apache CXF的帮助下,我成功地实现了[以编程方式将webservice发布到tomcat]。
这里是一个简化的工作示例:
我继承了一个CXFNonSpringServlet并在web.xml中注册它:
<servlet>
 <servlet-name>MyCXFServlet</servlet-name>
 <display-name>CXF Servlet</display-name>
 <servlet-class>de.test.MyCXFServlet</servlet-class>
 <load-on-startup>2</load-on-startup>
 <async-supported>true</async-supported>
</servlet>

<servlet-mapping>
 <servlet-name>MyCXFServlet</servlet-name>
 <url-pattern>/soap/*</url-pattern>
</servlet-mapping>

这是我的子类化的 CXFNonSpringServlet
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.HashSet;
import java.util.Set;
import javax.jws.WebMethod;
import javax.servlet.ServletConfig;
import org.apache.cxf.endpoint.Server;
import org.apache.cxf.frontend.ServerFactoryBean;
import org.apache.cxf.service.factory.ReflectionServiceFactoryBean;
import org.apache.cxf.transport.servlet.CXFNonSpringServlet;

public class MyCXFServlet extends CXFNonSpringServlet
{
    @Override
    protected void loadBus(ServletConfig sc) 
    {
        super.loadBus(sc);
        publishServices();
    }

    private void publishServices()
    {
        Set<Class> serviceInterfaces = new HashSet<>();
        serviceInterfaces.add(de.test.IUserService.class);
        serviceInterfaces.add(de.test.ILoginService.class);

        for (Class aSVCInterface : serviceInterfaces)
        {
            final String serviceName = aSVCInterface.getSimpleName();

            try
            {
                ReflectionServiceFactoryBean reflectionFactory = new ReflectionServiceFactoryBean(){
                    @Override
                    protected boolean isValidMethod(Method method)
                    {
                        boolean ret = super.isValidMethod(method);
                        WebMethod wm = method.getAnnotation(WebMethod.class);
                        if (wm != null && wm.exclude())
                            ret = false;
                        return ret;
                    }

                    @Override
                    protected String getServiceName() //Override for custom service name
                    {
                        return serviceName;
                    }

                };
                reflectionFactory.setServiceClass(aSVCInterface);

                Object proxiedServiceObject = Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[]{aSVCInterface}, new de.test.MyWebServiceInvocationHandler(aSVCInterface));

                ServerFactoryBean factory = new ServerFactoryBean(reflectionFactory);
                factory.setBus(getBus());
                factory.setServiceClass(aSVCInterface);
                factory.setServiceBean(proxiedServiceObject);
                factory.setAddress("/" + serviceName);
                Server svr = factory.create();    
                svr.getEndpoint().getInInterceptors().add(new de.test.MyServiceInterceptor());
            }
            catch (Exception exception)
            {
                exception.printStackTrace();
            }
        }
    }
}

上述Servlet将发布2个简单接口作为SOAP-WebService。
实现是动态的(代理)。
这是我的MyServiceInterceptor
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import org.apache.cxf.binding.soap.SoapMessage;
import org.apache.cxf.binding.soap.interceptor.AbstractSoapInterceptor;
import org.apache.cxf.endpoint.Endpoint;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.message.Exchange;
import org.apache.cxf.phase.Phase;
import org.apache.cxf.service.Service;
import org.apache.cxf.service.invoker.BeanInvoker;
import org.apache.cxf.service.invoker.Invoker;

public class MyServiceInterceptor extends AbstractSoapInterceptor
{
    public MyServiceInterceptor() 
    {
        super(Phase.PRE_INVOKE);
    }

    @Override
    public void handleMessage(SoapMessage p_message) throws Fault 
    {
        final Exchange exchange = p_message.getExchange();
        final Endpoint endpoint = exchange.get(Endpoint.class);
        final Service service = endpoint.getService();
        final Invoker invoker = service.getInvoker();

        if (invoker instanceof BeanInvoker)
        {
            BeanInvoker bi = (BeanInvoker)invoker;
            Object serviceObj = bi.getServiceObject(null);
            if (Proxy.isProxyClass(serviceObj.getClass()))
            {
                InvocationHandler ih = Proxy.getInvocationHandler(serviceObj);
                if (ih instanceof MyWebServiceInvocationHandler)
                {
                    MyWebServiceInvocationHandler h = (MyWebServiceInvocationHandler)ih;
                    h.setSoapMessage(p_message);
                }
            }
        }
    }
}

MyServiceInterceptor类主要用于将当前SOAP消息注入到 MyWebServiceInvocationHandler 中。

我认为, MyWebServiceInvocationHandler (这里不需要代码)负责调用真实的服务方法。它只实现了 InvocationHandler 并具有用于Soap-Message的字段(请参见 MyServiceInterceptor )。这是获取SOAPMessage详细信息(如Header)所需的。

希望这可以帮助您。
干杯!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接