欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Web Service 的 Provider 服务形式

程序员文章站 2022-05-18 09:25:44
...

本文不对jax-ws使用的细节进行讲解(只捞干货),请谅解。

采用的开发框架 : jax-ws

 

特点:服务端与客户端都是直接操作 SOAP 的全部消息内容。免去不必要的网络传输和xml的串行/解串行

约定的URI:http://[host]:[port]/[web-app-name]/service/[business-name]/[select|delete|update|insert]?[query-strings]

  业务名称(business-name)在URI上体现(借用不合适的词汇--资源)

  业务操作只规定四种: select(查询),delete(删除),update(更改),insert(新增) 。业务操作在URI体现出来(RPC形式)

 

实现的原理:根据约定的URI反射出业务的实现类(根据URI上的business-name) ;根据URI上的操作([select|delete|update|insert])定位到具体的业务实现类上的方法并执行

 

先来看服务的入口

 

 

@ServiceMode(value = Service.Mode.MESSAGE)
@WebServiceProvider(serviceName = "TimingSOAPWS", portName = "TimingSOAPWSPort", targetNamespace = "http://www.timing.com")
@BindingType(value = SOAPBinding.SOAP12HTTP_MTOM_BINDING)
@MTOM(enabled = true, threshold = 10 * 1024 * 1024)//10M的文件才启用MTOM
public final class TimingSOAPWS implements AsyncProvider<SOAPMessage> {
    public void invoke(SOAPMessage request, AsyncProviderCallback<SOAPMessage> callback, WebServiceContext context) {

        javax.servlet.ServletContext servletContext = (javax.servlet.ServletContext)context.getMessageContext().get(MessageContext.SERVLET_CONTEXT);

        final Runnable processRunnable = new ProcessRunnable(request, callback, context);

        //如果 servlet 环境里有线程池,则使用线程池
        if (servletContext != null) {

            Object o = servletContext.getAttribute(WSProviderThreadPoolListener.THREAD_POOL_ATTR);

            if (o instanceof ExecutorService)
                ((ExecutorService)o).execute(processRunnable);

        }
        else//没有线程池,则启动新线程
            new Thread(processRunnable).start();
    }
}

 

 

接下来,抽象出业务的操作

 

import javax.xml.ws.*;
/**
 * 抽象业务处理器。定义了 插入,更新,删除,查询
 * @author Hardneedl
 */
public interface WSOperator <S, R> {
    /**
     * 插入数据的操作
     * @param request 请求的报文
     * @param context web 上下文环境  @return 将要向客户端打回的内容
     */
    R insert(S request, WebServiceContext context) throws Exception;

    /**
     * 更新数据的操作
     * @param request 请求的报文
     * @param context web 上下文环境
     * @return 将要向客户端打回的内容
     */
    R update(S request, WebServiceContext context) throws Exception;

    /**
     * 删数据的操作
     * @param request 请求的报文
     * @param context web 上下文环境
     * @return 将要向客户端打回的内容
     */
    R delete(S request, WebServiceContext context) throws Exception;

    /**
     * 查数据的操作
     * @param request 请求的报文
     * @param context web 上下文环境
     * @return 将要向客户端打回的内容
     */
    R select(S request, WebServiceContext context) throws Exception;
}

 

最后来看关键的实现代码

 

final class ProcessRunnable implements Runnable {
    private SOAPMessage request;
    private AsyncProviderCallback<SOAPMessage> callback;
    private WebServiceContext context;

    ProcessRunnable(SOAPMessage request, AsyncProviderCallback<SOAPMessage> callback, WebServiceContext context) {
        this.request=request;
        this.callback=callback;
        this.context=context;
    }

    public void run() {

        MessageContext msgContext = context.getMessageContext();
        String pathString=(String)msgContext.get(MessageContext.PATH_INFO);

        if (pathString==null||pathString.isEmpty())return;

        String pathInfos[] = pathString.split("/");

        try {
            WSOperator opt = ClzManagerFactory.getClzManager().getOperatorSingleInstance("com.timing.business."+pathInfos[1] + "Operator");

            Method method = opt.getClass().getDeclaredMethod(pathInfos[2], SOAPMessage.class, WebServiceContext.class);
            SOAPMessage soapMessage = (SOAPMessage)method.invoke(opt,request,context);
            callback.send(soapMessage);

        }catch (Exception e) {            
            callback.sendError(e);
        }

    }
}

 

相比 WSDL->java的方式有何优势?

  1) 就四种操作方法,服务的操作简单清晰

  2) 复杂业务情形下,客户端post大型内容到服务端的时候,直接操作xml,免去jax-ws runtime 对于 xml-> java 类型的解串行操作。解串行操作消耗了更多的cpu和内存

  3) 简单业务需求的时候,直接在 URI 上用查询字符串提供参数,这也是免去jax-ws runtime 对于 xml-> java 类型的解串行操作

 

  wsdl->java 的开发方式中,服务端即使返回一个Integer类型,都需要 java->xml,然后客户端 xml->java

 

WSOperator的一个示范实现

/*这是一个适配器,具体业务实现者继承自这个类*/
public class WSOperatorAdapter implements WSOperator<SOAPMessage, SOAPMessage> {
    public SOAPMessage insert(SOAPMessage request, WebServiceContext context) throws Exception {return request;}
    public SOAPMessage update(SOAPMessage request, WebServiceContext context) throws Exception {return request;}
    public SOAPMessage delete(SOAPMessage request, WebServiceContext context) throws Exception {return request;}
    public SOAPMessage select(SOAPMessage request, WebServiceContext context) throws Exception {return request;}
}

 

final public class SiteInfoOperator extends WSOperatorAdapter{
    static private final Config CONFIG = ConfigFactory.getTextConfig();

    /**
     * 输出的 xml 结构
     *  <SiteInfo pollutantSourceCode=""
     *            drainOutletCode=""
     *            drainOutletName=""
     *            equipmentName=""
     *            deviceName=""
     *            scales=""
     *            groupType=""
     *            isNormal=""
     *            remarks=""
     *            userId=""
     *            itemClass=""/>
     *
     *
     * @param request
     * @param context
     * @return
     * @throws Exception
     */
    public SOAPMessage insert(SOAPMessage request, WebServiceContext context) throws Exception {
        String xmlString = ConvertorFactory.createSOAPBodyStringConvertor("SiteInfo").convert(request);
        Map<String,String> param = new HashMap<>(1);
        param.put("xml", xmlString);

        DaoFactory.createInsertDao("siteinfo.insert").perform(param);
        return WSMessageTool.createSimpleTextMessage(
            ConfigFactory.getTextConfig().getString("db.insert.ok")
        );
    }
}

 

相关标签: jax-ws web service