如何以编程方式将网络服务发布到 tomcat
How to programmatically publish webservice to tomcat
我想以编程方式将网络服务发布到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
and/orsun-jaxws.xml
(每项服务)
问题:
是否有任何已知的方法来完成它(使用 JAX-WS 或 Apache CXF 或...)?
(我知道已经发布了类似的问题。但是 none 确实回答了我的问题。)
这是对我自己问题的回答。
在 Apache CXF 的帮助下,我设法[以编程方式将 Web 服务发布到 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。
实现是动态的(Proxies)
这是我的 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
(我想,这里不需要代码)负责调用真正的服务方法。它只是实现 InvocationHandler
并且有一个用于 Soap-Message 的字段(参见 MyServiceInterceptor
)。这是获取 SOAPMessage-Details(如 Header)所必需的。
希望对您有所帮助。
干杯!
我想以编程方式将网络服务发布到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
and/orsun-jaxws.xml
(每项服务)
问题:
是否有任何已知的方法来完成它(使用 JAX-WS 或 Apache CXF 或...)?
(我知道已经发布了类似的问题。但是 none 确实回答了我的问题。)
这是对我自己问题的回答。
在 Apache CXF 的帮助下,我设法[以编程方式将 Web 服务发布到 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。
实现是动态的(Proxies)
这是我的 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
(我想,这里不需要代码)负责调用真正的服务方法。它只是实现 InvocationHandler
并且有一个用于 Soap-Message 的字段(参见 MyServiceInterceptor
)。这是获取 SOAPMessage-Details(如 Header)所必需的。
希望对您有所帮助。
干杯!