我想以编程方式向tomcat发布web服务.
例如JAX-WS或Apache CXF
与Endpoint.publish(…)类似.
例如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或……)?
(我知道已经发布了类似的问题.但是他们都没有回答我的问题.)
解决方法
这是我自己的问题.
我设法在Apache CXF的帮助下[以编程方式将webservice发布到tomcat].
我设法在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-Class主要用于将当前SOAPMessage注入MyWebServiceInvocationHandler.
我的MyWebServiceInvocationHandler(我认为,这里不需要代码)负责调用真正的Service-Method.它只是实现了InvocationHandler并且有一个Soap-Message字段(参见MyServiceInterceptor).这是获取SOAPMessage-Details(如Header)所必需的.
希望这可以帮助.干杯!