• Java WebService 教程系列之 Spring 整合 CXF


    Java WebService 教程系列之 Spring 整合 CXF

    一、引入 jar 包

    <dependency>
        <groupId>org.apache.cxf</groupId>
        <artifactId>cxf-rt-frontend-jaxws</artifactId>
        <version>3.1.8</version>
    </dependency>
    <dependency>
        <groupId>org.apache.cxf</groupId>
        <artifactId>cxf-rt-transports-http</artifactId>
        <version>3.1.8</version>
    </dependency>
    

    二、创建服务器端程序

    1.1 创建接口

    @WebService
    public interface HelloWebService {
    
        String sayHello();
    
        String sayWait();
    }
    

    1.2 接口实现类

    @WebService(endpointInterface= "com.github.binarylei.webservice.test1.HelloWebService", serviceName="HelloWebService")
    public class HelloWebServiceImpl implements HelloWebService {
    
        @Override
        public String sayHello() {
            System.out.println("hello world!");
            return "hello, binarylei";
        }
    
        @Override
        public String sayWait() {
            try {
                Thread.sleep(1000 * 10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "please, wait me";
        }
    }
    

    1.3 Spring 配置文件 spring-context-cxf.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:jaxws="http://cxf.apache.org/jaxws"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd 
           http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">
    
        <bean id="jaxWsServiceFactoryBean" class="org.apache.cxf.jaxws.support.JaxWsServiceFactoryBean">
            <property name="wrapped" value="true" />
        </bean>
    
        <jaxws:endpoint id="serviceimpl" address="/HelloWebService"
                        implementor="com.github.binarylei.webservice.test1.HelloWebServiceImpl">
    
            <jaxws:serviceFactory>
                <ref bean="jaxWsServiceFactoryBean" />
            </jaxws:serviceFactory>
        </jaxws:endpoint>
    </beans>
    

    1.4 配制 web.xml

    在 web.xml 中添加如下配制:

    <servlet>
        <servlet-name>CXFServlet</servlet-name>
        <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>CXFServlet</servlet-name>
        <url-pattern>/service/*</url-pattern>
    </servlet-mapping>
    

    1.4 启动 web 工程

    访问 http://localhost:8080/service/ 时,这时浏览器页面会出现:

    websevice 访问

    三、创建客户端程序

    public static void main(String[] args) {
        JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
        factory.setServiceClass(MyWebService.class);
        factory.setAddress("http://localhost:8080/service/MyWebService");
        MyWebService service = (MyWebService)factory.create();
    
        // 返回 "hello, binarylei"
        System.out.println(service.sayHello());
    }
    

    若服务无法访问,会抛出 javax.xml.ws.WebServiceException 的异常。

    四、客户端超时设置

    在使用网络服务时,通常需要为客户端设置请求超时时间,以避免长时间的去连接不可用的服务器。在 CXF 环境中,客户端可以通过两个参数配置超时限制。

    下面主要介绍 CXF WebService 客户端如何设置超时时间,以及相关参数的介绍。

    public static void main(String[] args) {
        JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
        factory.setServiceClass(MyWebService.class);
        factory.setAddress("http://localhost:8080/service/MyWebService");
        MyWebService service = (MyWebService)factory.create();
    
        // 设置客户端的配置信息,超时等.
        Client client = ClientProxy.getClient(service);
        HTTPConduit http = (HTTPConduit) client.getConduit();
        HTTPClientPolicy policy = new HTTPClientPolicy();
        policy.setConnectionTimeout(10000); // 连接超时时间
        policy.setReceiveTimeout(5000);     // 请求超时时间.
        http.setClient(policy);
    
        long startTime = System.currentTimeMillis();
    
        try {
            service.sayHello();
        } catch (Exception e) {
            System.out.println(e.getClass().getName());
            if (e.getCause() instanceof SocketTimeoutException) {
                System.out.println("响应超时");
            } else if (e.getCause() instanceof ConnectException) {
                System.out.println("不能连接");
            } else {
                System.out.println("未知错误");
            }
        }
        System.out.println(System.currentTimeMillis() - startTime);
    }
    

    超时主要有两个配置:

    • ConnectionTimeout: WebService 是基于 TCP 连接的,因此这个属性可以理解为设置 TCP 握手时间,若超出这个时间就认为连接超时。默认的时间单位是毫秒,默认设置是 30000 毫秒,即30秒。

    • ReceiveTimeout: 这个属性表示发送 WebService 请求后所等待响应的时间,若超过设置的时间则认为超时。默认的时间单位是毫秒,默认设置是 60000 毫秒,即60秒。

    五、踩过的坑

    5.1 No bean named 'cxf' is defined

    javax.servlet.ServletException: Servlet.init() for servlet [CXFServlet] threw exception
        org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:478)
        org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81)
        org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:650)
        org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342)
        org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:803)
        org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
        org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868)
        org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1459)
        org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
        java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
        java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
        org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
        java.lang.Thread.run(Thread.java:745)
    Root Cause
    
    org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'cxf' is defined
        org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:698)
        org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1175)
        org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:284)
        org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
        org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1060)
        org.apache.cxf.transport.servlet.CXFServlet.loadBus(CXFServlet.java:80)
        org.apache.cxf.transport.servlet.CXFNonSpringServlet.init(CXFNonSpringServlet.java:77)
        org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:478)
        org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81)
        org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:650)
        org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342)
        org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:803)
        org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
        org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868)
        org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1459)
        org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
        java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
        java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
        org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
        java.lang.Thread.run(Thread.java:745)
    

    最后发现没有在 web.xml 中加载 spring-context-cxf.xml ,真是自己坑了自己。

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring-context.xml</param-value>
    </context-param>
    

    5.2 java.lang.AbstractMethodError: org.apache.xerces.dom.DeferredDocumentImpl.setXmlStandalone

    方法具体的服务(http://localhost:8080/service/HelloWebService?wsdl)时报以下 bug:

    javax.servlet.ServletException: Servlet execution threw an exception
        org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    Root Cause
    
    java.lang.AbstractMethodError: org.apache.xerces.dom.DeferredDocumentImpl.setXmlStandalone(Z)V
        org.apache.cxf.frontend.WSDLGetUtils.updateDoc(WSDLGetUtils.java:301)
        org.apache.cxf.frontend.WSDLGetUtils.writeWSDLDocument(WSDLGetUtils.java:674)
        org.apache.cxf.frontend.WSDLGetUtils.getDocument(WSDLGetUtils.java:149)
        org.apache.cxf.frontend.WSDLGetInterceptor.getDocument(WSDLGetInterceptor.java:129)
        org.apache.cxf.frontend.WSDLGetInterceptor.handleMessage(WSDLGetInterceptor.java:77)
        org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:308)
        org.apache.cxf.transport.ChainInitiationObserver.onMessage(ChainInitiationObserver.java:121)
        org.apache.cxf.transport.http.AbstractHTTPDestination.invoke(AbstractHTTPDestination.java:252)
        org.apache.cxf.transport.servlet.ServletController.invokeDestination(ServletController.java:234)
        org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:208)
        org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:160)
        org.apache.cxf.transport.servlet.CXFNonSpringServlet.invoke(CXFNonSpringServlet.java:180)
        org.apache.cxf.transport.servlet.AbstractHTTPServlet.handleRequest(AbstractHTTPServlet.java:299)
        org.apache.cxf.transport.servlet.AbstractHTTPServlet.doGet(AbstractHTTPServlet.java:223)
        javax.servlet.http.HttpServlet.service(HttpServlet.java:635)
        org.apache.cxf.transport.servlet.AbstractHTTPServlet.service(AbstractHTTPServlet.java:274)
        org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    

    xerces jar 包冲突,我的项目中将之前想入的 xerces 注释的可以正常访问了。

    <dependency>
        <groupId>xerces</groupId>
        <artifactId>xerces</artifactId>
        <version>2.4.0</version>
    </dependency>
    

    参考:

    1. CXF 超时设置: http://blog.csdn.net/bruce_6/article/details/48048153

    2. CXF WebService 搭建: http://blog.csdn.net/dongdong9223/article/details/53169020

  • 相关阅读:
    OpenCV中的霍夫线变换和霍夫圆变换
    霍夫圆变换
    异或的性质及运用
    不用中间变量交换两个数值变量的值
    图像变换
    STM32程序的启动
    RAM与FLASH
    STM8的AIR与STM32的Keil的指定地址存数据
    HEX与ASCII之间装换
    STM32、Cortex-A、Cortex-R、Cortex-M、SecurCore
  • 原文地址:https://www.cnblogs.com/binarylei/p/8443236.html
Copyright © 2020-2023  润新知