1.使用JDK6自带的JAX-WS + Jboss4.2.3 开发WebService发布WebService报错? java.lang.ClassNotFoundException: com.sun.xml.ws.transport.http.servlet.WSServletContextListener
?
解释:JDK本身不带基于Servlet的代码,自带的jax-ws 不带WSServlet和WSServletContextListener两个类,在j2ee的jar包里才有
?
解决方案:
? ? a.使用代码中Endpoint.publish()发布(轻量级HTTP Server);
? ? ? ?
Endpoint.publish("http://localhost:8080/HelloService", new HelloSEI());
? ? 缺点是每次代码发布很麻烦,修改也麻烦,而且每个IP和端口只能发布一个
?
? ? b.使用Spring自带的SimpleJaxWsServiceExporter发布(轻量级HTTP Server);
? ? ? ?
<bean class="org.springframework.remoting.jaxws.SimpleJaxWsServiceExporter"> <property name="baseAddress" value="http://localhost:8080/"/> </bean> <bean id="accountServiceEndpoint" class="example.AccountServiceEndpoint"> ... </bean>
? ??缺点是每个IP和端口只能发布一个
?
? ? c.使用jaxws-spring.jar提供的WSSpringServlet方式发布(Servlet发布):
? ? ? ? 这需要使用到2个额外的jar包:
? ? ? ? jaxws-spring-1.8.jar
? ? ? ? xbean-spring-v2-2.8.jar
? ? ? ? 配置方式:
? ? ? ? web.xml
<web-app> <!-- this is for Spring --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- these are for JAX-WS --> <servlet> <servlet-name>jaxws-servlet</servlet-name> <servlet-class>com.sun.xml.ws.transport.http.servlet.WSSpringServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>jaxws-servlet</servlet-name> <url-pattern>/add</url-pattern> </servlet-mapping> ... if you deploy more services, you might need more <servlet-mapping>s ... </web-app>
? ??
? ? applicationContext.xml
? ??
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ws="http://jax-ws.java.net/spring/core" xmlns:wss="http://jax-ws.java.net/spring/servlet" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://jax-ws.java.net/spring/core http://jax-ws.java.net/spring/core.xsd http://jax-ws.java.net/spring/servlet http://jax-ws.java.net/spring/servlet.xsd"> <wss:binding url="/add" service="#addService" /> <wss:binding url="/sub"> <wss:service><!-- nested bean is of course fine --> <ws:service bean="#myService" /> </wss:service> </wss:binding> <!-- this bean implements web service methods --> <bean id="myService" class="foo.MyService" /> <!-- simplest definition only needs the class name --> <ws:service id="addService" impl="foo.MyAddService" handlers="#myHandler"/> <bean id="myHandler" class="foo.MyHandler" /> </beans>
?
2.Client端同样部署在jboss web容器上的时候,客户端调用报: java.lang.ClassCastException: com.sun.xml.ws.client.WSServiceDelegate cannot be cast to javax.xml.ws.spi.ServiceDelegate21
?
解释: 这是由于JBOSS有自带的jax-ws api的实现,称为jbossws。导致api类实现冲突。
解决方案:
思路是将JDK总的JAX-WS实现相关的类替换为加载JBOSS的JAX-WS API实现类。
?
做法是将jboss/lib/endorsed/ 目录下的:
? ? ? ? ? ? ? ? ? jboss-jaxrpc.jar
? ? ? ? ? ? ? ? ? jboss-jaxws.jar
? ? ? ? ? ? ? ? ? jboss-jaxws-ext.jar
? ? ? ? ? ? ? ? ? jboss-saaj.jar
? ? ? ? ? ? ? ? ? xercesImpl.jar
拷贝到%JAVA_HOME%/jre/endorsed/目录下。(这使用了JDK的endorsed机制,请查阅相关资料)
JDK的endorsed目录可以根据System.getProperty("java.endorsed.dirs")获得。 需要注意的是:在web容器使用哪个JDK就在那个JDK下面去修改。
?
3.发布的wsdl里面如果import 了wsdl和xsd文件时,客户端访问每次都会Addressing,如何将本地war包里面的xsd和wsdl和发布的服务绑定上?
解释:这个是由于WS的机制造成的,JAX-WS官方提供了解决方案。
解决方案:采用添加jax-ws-catalog的方式,绑定本地的xsd和wsdl
?
<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog" prefer=" system"> < system systemId=" http://foo.org/hello?wsdl" uri="HelloService.wsdl"/> </catalog>
?
Jax-ws-catalog.xml的放置位置:
???wsimport?命令行或者ant任务
使用-catalog?可选参数,指定catalog file.?例如:
-catalog jax-ws-catalog.xml
?
???WebService客户端运行时环境
Classpath下的该目录:META-INF/jax-ws-catalog.xml
(.jar包中的META-INF/jax-ws-catalog.xml也算)
?
???轻量级的基于HTTP server (j2se)的endpoint发布
就是说是通过调用接口EndPoint.publish(),并指定了HttpServer的。
包括通过Spring的轻量级发布辅助类发布的:
org.springframework.remoting.jaxws.SimpleJaxWsServiceExporter
org.springframework.remoting.jaxws.SimpleHttpServerJaxWsServiceExporter
Classpath下的该目录:META-INF/jax-ws-catalog.xml
?
???基于Servlet的endpoint
WEB-INF/jax-ws-catalog.xml
?
???基于JSR 109标准的?EJB?模块发布
META-INF/jax-ws-catalog.xml
【备注】
笔者在使用CXF作为webservice实现的时候通过指定jax-ws-catalog.xml是能够很好的被加载解析。但是使用JDK自带的jax-ws或者Metro jax-ws RI时,使用JBOSS作为发布容器,始终不能正确执行jax-ws-catalog.xml中描述的?import wsdl/xsdschema引用替换,进一步调试发现是通过jndi的方式访问了jax-ws-catalog.xml,但是没达到使用本地wsdl/xsd的效果
?
4.如何采用endpoint的方式发布一个servcename下有多个portname的WebService?
how to publish multi port webservice with same serviceName?
解释:一般看JAX-WS RI上的例子或者Spring的两个http Stand alone publish 发布辅助类(上文提到的:Spring的轻量级发布辅助类),都看不到这方面的资料。是因为多 port 使用的比较少。
解决方案:扩展Spring提供的http endpoint pubish类 :AbstractJaxWsServiceExporter。
该类胡自动解析带有@WebService注解的初始化为Spring bean了的endpoint发布类,并基于配置的basepath进行发布,发布地址:http://hostname:port/basepath/serviceName/portName
?
代码:
import java.net.InetSocketAddress; import java.util.List; import javax.jws.WebService; import javax.xml.ws.Endpoint; import javax.xml.ws.WebServiceProvider; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.remoting.jaxws.AbstractJaxWsServiceExporter; import com.sun.net.httpserver.Authenticator; import com.sun.net.httpserver.Filter; import com.sun.net.httpserver.HttpContext; import com.sun.net.httpserver.HttpServer; public class PortableHttpServerJaxWsServiceExporter extends AbstractJaxWsServiceExporter { private static final Logger LOG = LoggerFactory.getLogger(PortableHttpServerJaxWsServiceExporter.class); public PortableHttpServerJaxWsServiceExporter() { port = 8080; backlog = -1; shutdownDelay = 0; basePath = "/"; localServer = false; } public void setServer(HttpServer server) { this.server = server; } public void setPort(int port) { this.port = port; } public void setHostname(String hostname) { this.hostname = hostname; } public void setBacklog(int backlog) { this.backlog = backlog; } public void setShutdownDelay(int shutdownDelay) { this.shutdownDelay = shutdownDelay; } public void setBasePath(String basePath) { this.basePath = basePath; } public void setFilters(List<Filter> filters) { this.filters = filters; } public void setAuthenticator(Authenticator authenticator) { this.authenticator = authenticator; } @Override public void afterPropertiesSet() throws Exception { if (server == null) { InetSocketAddress address = (hostname == null ? new InetSocketAddress( port) : new InetSocketAddress(hostname, port)); server = HttpServer.create(address, backlog); if (logger.isInfoEnabled()) logger.info((new StringBuilder( "Starting HttpServer at address ")).append(address) .toString()); server.start(); localServer = true; LOG.info("Start http server successful. hostname: {}, port: {}", hostname, port); } super.afterPropertiesSet(); } @Override protected void publishEndpoint(Endpoint endpoint, WebService annotation) { endpoint.publish(buildHttpContext(endpoint, annotation.serviceName(), annotation.portName())); } @Override protected void publishEndpoint(Endpoint endpoint, WebServiceProvider annotation) { endpoint.publish(buildHttpContext(endpoint, annotation.serviceName(), annotation.portName())); } protected HttpContext buildHttpContext(Endpoint endpoint, String serviceName, String portName) { String fullPath = calculateEndpointPath(endpoint, serviceName, portName); HttpContext httpContext = server.createContext(fullPath); if (filters != null) httpContext.getFilters().addAll(filters); if (authenticator != null) httpContext.setAuthenticator(authenticator); LOG.info("Listen http context at full path : {}.", httpContext.getPath()); return httpContext; } protected String calculateEndpointPath(Endpoint endpoint, String serviceName, String portName) { if (null == portName) { return (new StringBuilder(String.valueOf(basePath))).append( serviceName).toString(); } return (new StringBuilder(String.valueOf(basePath))) .append(serviceName).append("/").append(portName).toString(); } @Override public void destroy() { super.destroy(); if (localServer) { logger.info("Stopping HttpServer"); server.stop(shutdownDelay); } } protected final Log logger = LogFactory.getLog(getClass()); private HttpServer server; private int port; private String hostname; private int backlog; private int shutdownDelay; private String basePath; private List<Filter> filters; private Authenticator authenticator; private boolean localServer; }
?
发布方式:
<bean class="com.huawei.ossj.ws.publisher.PortableHttpServerJaxWsServiceExporter"> <property name="basePath" value="/" /> <property name="port" value="19900" /> </bean>
?
?
?
?