加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

WebService交互

发布时间:2020-12-17 00:17:24 所属栏目:安全 来源:网络整理
导读:1.3?一个简单的WebService运行实例 WebService代码: package ?stock.server ; @ javax.jws. WebService public ? class ?StockQuoteProvider ?{ ??? public ?StockQuoteProvider () { ???} ??? float ?getLastTradePrice (String tickerSymbol) { ?????? re

1.3?一个简单的WebService运行实例

WebService代码:

package?stock.server;

@javax.jws.WebService

public?class?StockQuoteProvider?{

???public?StockQuoteProvider () {

???}

???float?getLastTradePrice (String tickerSymbol) {

??????return?"abc".equals(tickerSymbol)? 1234.0f : 0.0f;

????}

}

客户端代码:

import?java.lang.annotation.Annotation;

import?stock.server.*;

import?javax.xml.ws.Service;

?

class?StockQuoteClient {

??????static?void?main(String[] args)?throwsException {

??????StockQuoteProviderService service =?newStockQuoteProviderService();

??????StockQuoteProvider port = service.getStockQuoteProviderPort();

???????????System.out.println(port.getLastTradePrice(args[0]));

??????}

}

?

?

2.?Web?Service技术研究的环境准备

2.1?安装运行环境

???推荐安装GlassFish服务器,具体安装方法可以参见以下文章:

手把手教你?怎么?安装?GlassFish

http://blog.csdn.net/nanjingjiangbiao/archive/2010/01/28/5264913.aspx

2.2?下载WebService API(JAX-WS)的源代码

???具体的下载URL参见以下地址:

https://jax-ws-sources.dev.java.net/source/browse/jax-ws-sources/

2.3?部署服务器端

1.把1.3中的服务器端部署到GlassFish中

2.用wsimport命令生成stub中间程序

3.把1.3中的客户端代码和stub代码,以及2.2下载的WebService源代码部署到Eclipse工程中,就可以DEBUG了。

具体的可以参照以下文章:

SOA研究之?JAX-WS

http://blog.csdn.net/nanjingjiangbiao/archive/2010/02/10/5305049.aspx

3.?Web?Service的技术内幕

3.1?客户端是如何和WSDL建立关系的?

???1.?首先,我们看到客户端程序中有以下这样一行

???StockQuoteProviderService?service =?new

?StockQuoteProviderService();

???2.?这行代码,会调用到

public?StockQuoteProviderService() {

????????super(STOCKQUOTEPROVIDERSERVICE_WSDL_LOCATION,?newQName("http://server.stock/",?"StockQuoteProviderService"));

????}

3.?这行代码,会调用到com.sun.xml.ws.spi.ProviderImpl的

@Override

????public?ServiceDelegate createServiceDelegate( URL wsdlDocumentLocation,QName serviceName,?Class?serviceClass) {

?????????return?new?WSServiceDelegate(wsdlDocumentLocation,serviceName,?serviceClass);

????}

4.?这行代码,会调用到com.sun.xml.ws.clientWSServiceDelegate的

/**

?????*?@param?serviceClass

?????*??????Either?{@link Service}.class?or?other?generatedservice-derived?classes.

?????*/

????public?WSServiceDelegate(@Nullable?Source wsdl,?@NotNullQName serviceName,100)">@NotNull?final?Class<??extends?Service> serviceClass) {

???????~省略~

????}

5.?而其中最关键的就是以下这段,解析阅读WSDL的代码,这段代码主要是用XMLStream来构建WSDL代码,不足为奇。

WSDLServiceImpl?service=null;

????????if?(wsdl !=?null) {

????????????try?{

????????????????URL url = wsdl.getSystemId()==null???null?:?newURL(wsdl.getSystemId());

????????????????WSDLModelImpl model = parseWSDL(url,wsdl);

????????????????service = model.getService(this.serviceName);

????????????????if?(service ==?null)

????????????????????throw?new?WebServiceException(

???????????????????????ClientMessages.INVALID_SERVICE_NAME(serviceName,

???????????????????????????buildNameList(model.getServices().keySet())));

????????????????// fill in statically known ports

????????????????for?(WSDLPortImpl port : service.getPorts())

????????????????????ports.put(port.getName(),85)">new?PortInfo(this,port));

????????????}?catch?(MalformedURLException e) {

????????????????newWebServiceException(ClientMessages.INVALID_WSDL_URL(wsdl.getSystemId()),e);

????????????}

????????}

????????wsdlService?= service;

3.2?客户端是如何和SEI建立关系的?

1.?首先,我们看到客户端程序中有以下这样一行

StockQuoteProvider port = service.getStockQuoteProviderPort();

2.?这行代码,会调用到com.sun.xml.ws.clientWSServiceDelegate的

private?<T> T?getPort(WSEndpointReference wsepr,QName portName,Class<T> portInterface,

??????????????????????????WebServiceFeature... features) {

????????SEIPortInfo spi = addSEI(portName,portInterface,features);

????????returncreateEndpointIFBaseProxy(wsepr,portName,features,spi);

????}

3.?这行代码,会调用到com.sun.xml.ws.clientWSServiceDelegate的

*?Creates?a?new?pipeline?for?the?given?port?name.

?????private?Tube?createPipeline(PortInfo portInfo,WSBinding binding) {

????????//Check all required WSDL extensions are understood

????????checkAllWSDLExtensionsUnderstood(portInfo,binding);

????????SEIModel seiModel =?if(portInfo?instanceof?SEIPortInfo) {

????????????seiModel = ((SEIPortInfo)portInfo).model;

????????}

????????BindingID bindingId = portInfo.bindingId;

????????TubelineAssembler assembler =TubelineAssemblerFactory.create(

????????????????Thread.currentThread().getContextClassLoader(),bindingId);

????????if?(assembler ==?null)

????????????new?WebServiceException("Unable to process bindingID="?+ bindingId);????//?TODO: i18n

????????return?assembler.createClient(

????????????????new?ClientTubeAssemblerContext(

????????????????????????portInfo.targetEndpoint,

????????????????????????portInfo.portModel,

????????????????????????container,((BindingImpl)binding).createCodec(),seiModel));

????}

在这段代码中,使用了TUBE技术,把客户端和服务器之间建立了关系。

4.?这行代码,会调用到com.sun.xml.ws.util.pipe.StandaloneTubeAssembler的

@NotNull

????public?Tube createClient(ClientTubeAssemblerContext context) {

????????Tube head = context.createTransportTube();

????????head = context.createSecurityTube(head);

????????if?(dump) {

????????????// for debugging inject a dump pipe. this is left in the production code,

????????????// as it would be very handy for a trouble-shooting at the production site.

????????????head = context.createDumpTube("client",System.out,head);

????????}

????????head = context.createWsaTube(head);

????????head = context.createClientMUTube(head);

????????head = context.createValidationTube(head);

????????return?context.createHandlerTube(head);???????

????}

?

在以上代码中,开始和SOAP绑定,准备发送请求和调用函数等等。

?

3.3?客户端是如何发送请求的?

port.getLastTradePrice(args[0])

2.?这行代码,会调用到com.sun.xml.ws.client.sei.SEIStub的

public?Object invoke(Object proxy,Method method,Object[] args)throws?Throwable {

????????MethodHandler handler =?methodHandlers.get(method);

????????if?(handler !=?return?handler.invoke(proxy,args);

????????}?else?{

????????????// we handle the other method invocations by ourselves

????????????try?{

????????????????return?method.invoke(????????????}?catch?(IllegalAccessException e) {

????????????????// impossible

????????????????new?AssertionError(e);

????????????}?catch?(IllegalArgumentException e) {

????????????????catch?(InvocationTargetException e) {

????????????????throw?e.getCause();

????????????}

????????}

????}

3.?这行代码,会调用到com.sun.xml.ws.client.stub的(中间省去了2层不重要的代码)

Passes?message?to?pipe?processing.

?????*?<p>

?????Unlike?{@link Tube}?instances,

?????this?method?is?threadsafe?and?can?be?invoked?from

?????multiple?threads?concurrently.

?????*

?????packet?????????The?sent?theserver

?????requestContext?{@link RequestContext}?wheninvocation?originally?scheduled.

?????*???????????????????????This?must?same?object?as{@link #requestContext}?synchronous

?????invocations,?but?asynchronousit?needs?snapshot

?????captured?at?point?ofinvocation,191)">correctly?satisfy?spec?requirement.

?????receiver???????Receives?{@link ResponseContext}.?Since?requires

?????that?asynchronous?invocationsnot?update?response?context,191)">depending?on?mode?of?invocationthey?have?go?different?places.

?????So?we?take?setter?abstractsaway.

?????protected?final?Packet process(Packet packet,RequestContext requestContext,ResponseContextReceiver receiver) {

????????configureRequestPacket(packet,requestContext);

????????Pool<Tube> pool =?tubes;

????????if?(pool ==?"close method has already been invoked");?: i18n

?

????????Fiber fiber =?engine.createFiber();

????????// then send it away!

????????Tube tube = pool.take();

?

????????try?{

????????????return?fiber.runSync(tube,packet);

????????}?finally?{

????????????// this allows us to capture the packet even when the call failed with an exception.

????????????// when the call fails with an exception it's no longer a 'reply' but it may provide some information

????????????// about what went wrong.

?

????????????// note that Packet can still be updated after

????????????// ResponseContext is created.

????????????Packet reply = (fiber.getPacket() ==?null) ? packet : fiber.getPacket();

????????????receiver.setResponseContext(newResponseContext(reply));

?

????????????pool.recycle(tube);

????????}

????}

4.?这行代码,会调用到com.sun.xml.ws.api.pipe.?__doRun的(中间省去了3层不重要的代码)

这段代码开始发送打成数据包的http请求

To?from?{@link #doRun(Tube)}.

?????@see?#doRun(Tube)

?????private?Tube __doRun(Tube next) {

????????final?Fiber old =?CURRENT_FIBER.get();

????????CURRENT_FIBER.set(this);

?

????????// if true,lots of debug messages to show what's being executed

????????final?boolean?traceEnabled =LOGGER.isLoggable(Level.FINER);

?

????????while(!isBlocking() && !needsToReenter) {

????????????????try?{

????????????????????NextAction na;

????????????????????Tube last;

????????????????????if(throwable!=null) {

????????????????????????contsSize==0) {

????????????????????????????// nothing else to execute. we are done.

????????????????????????????null;

????????????????????????}

????????????????????????last = popCont();

????????????????????????if(traceEnabled)

????????????????????????????LOGGER.finer(getName()+' '+last+".processException("+throwable+')');

????????????????????????na = last.processException(throwable);

????????????????????}?else?{

????????????????????????if(next!=null) {

????????????????????????????if(traceEnabled)

????????????????????????????????' '+next+".processRequest("+packet+')');

????????????????????????????na = next.processRequest(packet);

????????????????????????????last = next;

????????????????????????}?else?{

????????????????????????????contsSize==0) {

????????????????????????????????// nothing else to execute. we are done.

????????????????????????????????null;

????????????????????????????}

????????????????????????????last = popCont();

????????????????????????????".processResponse("+')');

????????????????????????????na = last.processResponse(packet);

????????????????????????}

????????????????????}

?~省略~

5.?这行代码,会调用到com.sun.xml.ws.encoding.?StreamSOAPCodec的(中间省去了无数层不重要的代码)的

public?ContentType encode(Packet packet,OutputStream out) {

????????if?(packet.getMessage() !=?null) {

????????????XMLStreamWriter writer = XMLStreamWriterFactory.create(out);

????????????try?{

????????????????packet.getMessage().writeTo(writer);

????????????????writer.flush();

????????????}?catch?(XMLStreamException e) {

????????????????new?WebServiceException(e);

????????????}

????????????XMLStreamWriterFactory.recycle(writer);

????????}

????????return?getContentType(packet.soapAction);

????}

大家可以看到,他发出请求了。

3.4?服务器端是如何接受请求的?

1.?首先,服务器端有一个名叫JAXWSServlet的Servlet常驻服务器,监听请求。所以,请求会首先被转发给com.sun.enterprise.webservice.JAXWSServlet的

????void?doPost(HttpServletRequest request,

??????????????????????????HttpServletResponse response)

????????throws?ServletException,IOException{

?????????/**

?????????requirement?came?jbi?team.?If?WebServiceEndpoint

?????????endpoint?which?private?throw?an?errorwhenever?get

?????????post?request?made

?????????*/

????????Endpoint endpt =

?wsEngine_.getEndpoint(request.getServletPath());

~省略~

2.最后,代码会调转到以下com.sun.xml.ws.transport.http.HttpAdapter的

class?HttpToolkit?extends?Adapter.Toolkit?{

????????void?handle(WSHTTPConnection con)?throws?IOException {

????????????boolean?invoke =?false;

????????????try?{

????????????????Packet packet =?new?Packet();

????????????????try?{

????????????????????packet = decodePacket(con,192)">codec);

????????????????????invoke =?true;

????????????????}?catch(ExceptionHasMessage e) {

????????????????????LOGGER.log(Level.SEVERE,255)">"JAXWS2015: An ExceptionHasMessage occurred. "?+ e.getMessage(),e);

????????????????????packet.setMessage(e.getFaultMessage());

????????????????}?catch(UnsupportedMediaException e) {

????????????????????"JAXWS2016: An UnsupportedMediaException occurred. "?+ e.getMessage(),e);

????????????????????con.setStatus(WSHTTPConnection.UNSUPPORTED_MEDIA);

????????????????}?catch(Exception e) {

????????????????????"JAXWS2017: A ServerRtException occurred. "?+ e.getMessage(),e);

???????????????????con.setStatus(HttpURLConnection.HTTP_INTERNAL_ERROR);

????????????????}

????????????????if?(invoke) {

????????????????????try?{

????????????????????????packet =?head.process(packet,con.getWebServiceContextDelegate(),

????????????????????????????????packet.transportBackChannel);

????????????????????}?catch(Exception e) {

????????????????????????"JAXWS2018: An Exception occurred. "?+ e.getMessage(),e);

????????????????????????if?(!con.isClosed()) {

????????????????????????????writeInternalServerError(con);

????????????????????????}

????????????????????????return;

????????????????????}

????????????????}

???????????????encodePacket(packet,con,192)">codec);

????????????}?finally?{

????????????????if?(!con.isClosed()) {

????????????????????con.close();

????????????????}

????????????}

????????}

????}

以上代码分为三块大的处理,分别是

packet = decodePacket(con,192)">codec);

packet =?????????????????????????????????packet.transportBackChannel);

encodePacket(packet,192)">codec);

用来解析数据包,调用服务,发送回复数据包。这里就不详细介绍了。

4.?总结

希望能够通过这样的文章,更清晰的,直白的把WebService的详细技术内幕公布给大家,为开源软件运动作一份自己的贡献。

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!