zoukankan      html  css  js  c++  java
  • servlet,jsp,axis webservice 的实现原理

    引用网络上一个好文

    servlet,jsp,axis webservice 的实现原理


    回顾一下servlet的映射模式。

    我们知道,servlet是从javax.servlet.http.HttpServlet继承的,在服务器端被载入JVM执行,然后向客户端输出html流。
    servlet的web.xml文件(位于 webapps/foo/WEB-INF目录):

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"
    "http://java.sun.com/j2ee/dtds/web-app_2.2.dtd">
    <web-app>
    <servlet-mapping>
    <servlet-name>invoker</servlet-name>
    <url-pattern>/servlet/*</url-pattern>
    </servlet-mapping>
    </web-app>


    invoker servlet 其实是:org.apache.catalina.servlets.InvokerServlet
    按类名提供小服务程序。例如,如果您调用 foo/servlet/HelloServlet,
    invoker servlet将装入该HelloServlet(如果它在其类路径中的话)并执行。

    初看上面的web.xml,好像只给出了一个servlet映射,而没有定义invoker servlet。
    其实,invoker servlet 是在tomcat的conf目录中的web.xml中定义的::
    <servlet>
    <servlet-name>invoker</servlet-name>
    <servlet-class>
    org.apache.catalina.servlets.InvokerServlet
    </servlet-class>
    <init-param>
    <param-name>debug</param-name>
    <param-value>0</param-value>
    </init-param>
    <load-on-startup>2</load-on-startup>
    </servlet>

    所以,如果抛开Tomcat_HOME/conf/web.xml,我们这样定义一个web.xml,似乎更能清楚的说明问题:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"
    "http://java.sun.com/j2ee/dtds/web-app_2.2.dtd">
    <web-app>
    <servlet-name>MyInvoker</servlet-name>
    <servlet-class>
    org.apache.catalina.servlets.InvokerServlet
    </servlet-class>
    <init-param>
    <param-name>debug</param-name>
    <param-value>0</param-value>
    </init-param>
    <load-on-startup>2</load-on-startup>
    </servlet>

    <servlet-mapping>
    <servlet-name>MyInvoker</servlet-name>
    <url-pattern>/servlet/*</url-pattern>
    </servlet-mapping>
    </web-app>


    即所有/servlet/* 模式的url,都会交给org.apache.catalina.servlets.InvokerServlet来处理。
    或者说,所有/servlet/* 模式的url,其实都是调用InvokerServlet这个类,而InvokerServlet本身也是
    一个servlet,它也是从 HttpServlet 继承而来的。

    这样,我们自己的servlet就能够通过特定的url执行,即 /servlet/OurServlet。
    当然,如果你高兴,可以定义任何的 url pattern,而不一定是 /servlet/*,这一点,正如我们后面
    看到的Axis处理Soap消息的方法。


    再进一步,如果不想让 InvokerServlet 在中间“捣鬼”,我们当然可以直接定义自己的servlet:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"
    "http://java.sun.com/j2ee/dtds/web-app_2.2.dtd">
    <web-app>
    <servlet-name>MyInvoker2</servlet-name>
    <servlet-class>
    com.foo.MyServlet
    </servlet-class>
    </servlet>

    <servlet-mapping>
    <servlet-name>MyInvoker2</servlet-name>
    <url-pattern>/AnyName/*</url-pattern>
    </servlet-mapping>
    </web-app>


    JSP也是一样的道理,有了上面的分析,
    看看Tomcat_HOME/conf/web.xml中的如下语句就可以JSP的处理方法了,这里就不再废话了:
    ....
    <servlet>
    <servlet-name>jsp</servlet-name>
    <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
    <init-param>
    <param-name>logVerbosityLevel</param-name>
    <param-value>WARNING</param-value>
    </init-param>
    <load-on-startup>3</load-on-startup>
    </servlet>
    <servlet-mapping>
    <servlet-name>jsp</servlet-name>
    <url-pattern>*.jsp</url-pattern>
    </servlet-mapping>
    ....


    下面进入正题。


    我们先来看部署Web Service的web.xml:

    <?xml version="1.0" encoding="ISO-8859-1"?>
    <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN" "http://java.sun.com/j2ee/dtds/web-app_2_2.dtd">

    <web-app>

    <servlet>
    <servlet-name>Axis</servlet-name>
    <!--实际servlet程序,这里是AxisServlet-->
    <servlet-class>org.apache.axis.transport.http.AxisServlet</servlet-class>
    </servlet>

    <!-- ### 定义servlet和url的对应关系-->

    <servlet-mapping>
    <servlet-name>Axis</servlet-name>
    <url-pattern>/services/*</url-pattern>
    </servlet-mapping>

    </web-app>


    所有 /services/* 模式的 url 都会交给org.apache.axis.transport.http.AxisServlet处理,
    AxisServlet当然也是从HttpServlet继承而来的。这就是为什么我们部署的Web服务在调用时都要在
    服务名称前加上 services/ 了。

    可以说,AxisServlet是所有Web服务调用的入口。
    那么AxisServlet在接手Web服务调用后都做了哪些工作呢?

    客户端用call.invoke()调用web服务用的是POST,所以入口是AxisServlet.doPost...
    而不是AxisServlet.doGet...


    先来看看AxisServlet的doPost函数,这里只给出了关键语句及注释:

    /**
    * Process a POST to the servlet by handing it off to the Axis Engine.
    * Here is where SOAP messages are received
    * @param req posted request
    * @param res respose
    * @throws ServletException trouble
    * @throws IOException different trouble
    */
    public void doPost(HttpServletRequest req, HttpServletResponse res)
    throws ServletException, IOException
    {
    msgContext = createMessageContext(engine, req, res);//获取客户请求信息

    engine.invoke(msgContext); //调用客户端请求的服务

    responseMsg = msgContext.getResponseMessage();//得到调用的返回结果

    sendResponse(getProtocolVersion(req), contentType, res, responseMsg);//将结果送至客户端
    }

    这样一来,Web服务调用的来龙去脉就大致清楚了。。。

    为了高清楚前面我们的三个url
    http://192.168.0.1/test/services
    http://192.168.0.1/test/services/sayHelloService?wsdl
    http://192.168.0.1/test/services/sayHelloService?method=sayHelloTo&aname=everybody
    是怎样获得输出结果的,再来看看AxisServlet的doGet函数,这里只给出了流程框架及注释:

    **
    * Process GET requests. Because Axis does not support the GET-style
    * pseudo execution of SOAP methods, this handler deals with queries
    * of various kinds, not real SOAP actions.
    *
    * @todo for secure installations, dont stack trace on faults
    * @param request request in
    * @param response request out
    * @throws ServletException
    * @throws IOException
    */
    public void doGet(HttpServletRequest req, HttpServletResponse res)
    throws ServletException, IOException
    {

    //如果路径为空,比如:http://localhost/wstk/services 或 http://localhost/wstk/services/*
    if((pathInfo == null || pathInfo.equals("")) && !realpath.endsWith(".jws"))

    {
    //从server-config.wsdd文件中读取所有部署的服务信息,向向客户端列出所有部署的服务,
    //包括每个服务可调用的方法。

    }else
    //如果路径不为空,比如:http://localhost/wstk/services/sayHelloService
    if(realpath != null)
    {
    //如果请求wsdl,比如:http://localhost/wstk/services/sayHelloService?wsdl
    if(wsdlRequested)
    {
    //创建sayHelloService的WSDL文件并传送至客户端
    } else
    //这里是利用url调用Web服务的入口,比如http://192.168.0.1/test/services/sayHelloService?method=sayHelloTo&aname=everybody
    if(req.getParameterNames().hasMoreElements())
    {
    //如果客户端调用的方法正确,则Axis会调用相应的JavaBean,并把JavaBean的返回结果
    //封装为Soap消息流返回给客户端。
    }
    }
    }


    而Axis怎样找到我们所请求的JavaBean呢?答案是server-config.wsdd文件。

    server-config.wsdd

    <?xml version="1.0" encoding="UTF-8"?>
    <deployment xmlns:java="http://xml.apache.org/axis/wsdd/providers/java" xmlns="http://xml.apache.org/axis/wsdd/">

    <service name="sayHelloService" provider="java:RPC">
    <parameter name="className" value="sayHello"/>
    <parameter name="allowedMethods" value="sayHelloTo"/>
    </service>

    <handler type="java:org.apache.axis.handlers.http.URLMapper" name="URLMapper"/>

    <transport name="http">
    <requestFlow>
    <handler type="URLMapper"/>
    </requestFlow>
    </transport>

    </deployment>

    WSDD是web service deployment descriptor的缩写。

    最外面的<deployment>元素指示这是WSDD,并定义了java的名字空间。

    接着的 <service>元素定义了service。一个service是一个目标链,包括请求request、内容提供者provider、响应response。
    在这个例子中,我们指出service名字是sayHelloService ,provider是"java:RPC",它是axis 的标记,指示这是一个java的RPC service,
    而处理它的真正的class是org.apache.axis.providers.java.RPCProvider。

    接着我们要在<parameter>中告诉RPCProvider,它如何实例化并调用正确的class(如:com.foo.MyService)。
    <parameter>元素的className指示class名,allowedMethods告诉引擎那些共用的方法要通过soap来调用。
    "*"表示所有的公共方法,我们也列出方法名字列表,可以空格或逗号分割它们。
  • 相关阅读:
    spring security 学习资料
    设计模式,学习资料
    知名博主
    shiro 学习资料
    nuxt 中使用 koa-session
    koa-session 知识点
    MySQL 中的默认数据库介绍
    JUnit 学习资料
    027_git添加多账号设置
    023_supervisorctl管理服务注意事项
  • 原文地址:https://www.cnblogs.com/cy163/p/1156162.html
Copyright © 2011-2022 走看看