在Java中创建、使用Web Service主要是通过JAX-RPC来进行的。
JAX-RPC Service Endpoint(JSE)和EJB Endpoint是Java Web Service的服务器端两种主要实现方式。而Java Web Service的客户端主要有:
- 生成的stub,它是最常用的,最接近Java RMI的语义;
- 动态代理;
- 动态调用接口
Java Web Service的服务器端实现
JSE是通过Servlet(下称JAX-RPC Servlet)响应来自客户端的SOAP消息的,JAX-RPC Servlet负责把SOAP消息转换为Java的方法调用,并调用响应的JSE。
实现一个JSE通常需要定义一个endpoint接口和相应的实现。接口中定义了作为web service的方法,该接口需要继承java.rmi.Remote,其所有方法必须抛java.rmi.RemoteException。
在Java中创建、使用Web Service主要是通过JAX-RPC来进行的。
JAX-RPC Service Endpoint(JSE)和EJB Endpoint是Java Web Service的服务器端两种主要实现方式。而Java Web Service的客户端主要有:
- 生成的stub,它是最常用的,最接近Java RMI的语义;
- 动态代理;
- 动态调用接口
Java Web Service的服务器端实现
JSE是通过Servlet(下称JAX-RPC Servlet)响应来自客户端的SOAP消息的,JAX-RPC Servlet负责把SOAP消息转换为Java的方法调用,并调用响应的JSE。
实现一个JSE通常需要定义一个endpoint接口和相应的实现。接口中定义了作为web service的方法,该接口需要继承java.rmi.Remote,其所有方法必须抛java.rmi.RemoteException。示例如下:
package some.dot.com;
public interface BookQuote extends java.rmi.Remote {
public float getBookPrice(String isbn) throws java.rmi.RemoteException;
}
在J2EE环境下可以通过以多种式实现endpoint接口,一般都是先通过JNDI找到相关的资源,然后调用资源上的相应的方法。典型的实现有:
1.通过JDBC访问数据库
public class BookQuote_Impl_2 implements BookQuote {
public float getBookPrice(String isbn){
java.sql.Connection jdbcConnection = null;
java.sql.Statement sqlStatement = null;
java.sql.ResultSet resultSet;
try {
javax.naming.InitialContext jndiEnc =
new javax.naming.InitialContext();
javax.sql.DataSource dataSource = (javax.sql.DataSource)
jndiEnc.lookup("java:comp/env/jdbc/DataSource");
jdbcConnection = dataSource.getConnection();
sqlStatement = jdbcConnection.createStatement();
resultSet = sqlStatement.executeQuery(
"SELECT wholesale FROM CATALOG WHERE isbn = /'"+isbn+"/'");
if(resultSet.next()){
float price = resultSet.getFloat("wholesale");
return price;
}
return 0;// zero means it's not stocked.
}catch (java.sql.SQLException se) {
throw new RuntimeException("JDBC access failed");
}catch (javax.naming.NamingException ne){
throw new RuntimeException("JNDI ENC access failed");
}
}
}
2.调用EJB
public class BookQuote_Impl_3 implements BookQuote {
public float getBookPrice(String isbn){
try {
javax.naming.InitialContext jndiEnc =
new javax.naming.InitialContext();
BookHomeLocal bookHome =(BookHomeLocal)
jndiEnc.lookup("java:comp/env/ejb/BookHomeLocal");
BookLocal book = bookHome.findByPrimaryKey(isbn);
return book.getWholesalePrice();
}catch(javax.naming.NamingException ne){
throw new RuntimeException("JNDI ENC access failed");
}catch(java.rmi.RemoteException re){
throw new RuntimeException("Problem invoking operation on Book EJB");
}catch(javax.ejb.FinderException fe){
throw new RuntimeException("Cannot find Book EJB");
}
}
}
3.使用JAX-RPC生成Stub调用其它的web service
public class BookQuote_Impl_4 implements BookQuote {
public float getBookPrice(String isbn){
try {
javax.naming.InitialContext jndiEnc = new javax.naming.InitialContext();
ImsCatalogService webService =(ImsCatalogService)
jndiEnc.lookup("java:comp/env/service/ImsCatalogService");
CatalogPort catalog = webService.getCatalogPort();
return catalog.getWholesalePrice(isbn);
}catch (javax.xml.rpc.ServiceException se) {
throw new RuntimeException("JAX-RPC ServiceException thrown");
}catch (javax.xml.rpc.JAXRPCException je) {
throw new RuntimeException("JAXRPCException thrown");
}catch (java.rmi.RemoteException re){
throw new RuntimeException("RemoteException thrown");
}catch (javax.naming.NamingException ne){
throw new RuntimeException("NamingException thrown");
}
}
}
4.调用JCA等
为方便JSE得到ServletContext和原始的SOAP消息等元信息,JAX-RPC定义了ServletEndpointContext,它是这些元信息载体,并通过让JSE实现ServiceLifecycle来传递ServletEndpointContext。
ServiceLifeCyle定义如下:
package javax.xml.rpc.server;
import javax.xml.rpc.ServiceException;
public interface ServiceLifecycle {
public void init(Object context) throws ServiceException;
public void destroy();
}
其中,init方法用来传递ServletEndpoinContext,destroy方法用来给JSE释放资源。
ServletEndpointContext定义如下:
package javax.xml.rpc.server;
public interface ServletEndpointContext {
public java.security.Principal getUserPrincipal();
public boolean isUserInRole(String role);
public javax.xml.rpc.handler.MessageContext getMessageContext();
public javax.Servlet.http.HttpSession getHttpSession()
throws javax.xml.rpc.JAXRPCException;
public javax.Servlet.ServletContext getServletContext();
}
方法getUserPrincipal,isUserInRole得到JAX-RPC Servlet的UserPrincipal, isUserInRole,这些方法仅适用于Web Service使用了HTTP Basic Authentication或HTTPS的情形。方法getHttpSession用于得到HttpSession。当在JSE中需要显式地处理 SOAP消息(如处理SOAP 消息头)时,可以调用方法getMessageContext得到MessageContext。
JSE支持单线程模式和多线程模式,但偏向于后者。所以,实现JSE时要注意对类成员变量访问的并发控制,或则让JSE变为无状态的。
可发Java Web Service也可以从web service定义本身入手,定义好WSDL。然后用工具生成endpoint的接口和实现的框架。为了增强不同平台的互操作性,定义WSDL的SOAP绑定时应尽量避免使用encoded。