? ? ? ? ?前言:WebService就目前来讲已经是一种成熟的技术了,目前对WebService支持的框架也很多,虽然本人并没有对各框架做个测试,但分析比较各框架的优缺点(较为主观),最后还是选择了CXF作为样例框架进行分析,主要是因为性能较佳,支持JAX-WS,Spring无缝集成,上手快等特点,本文旨在提供CXF基本入门demo,帮助快速入门了解CXF的使用。
本篇文章重点关注以下问题:
???? Apache CXF 是一个开源的 WebServices 框架,CXF 帮助您利用 Frontend 编程 API 来构建和开发 Services ,像 JAX-WS 。这些 Services 可以支持多种协议,比如:SOAP、XML/HTTP、RESTful HTTP 或者CORBA?,并且可以在多种传输协议上运行,比如:HTTP、JMS 或者 JBI,CXF 大大简化了 Services 的创建,同时它继承了 XFire 传统,一样可以天然地和 Spring 进行无缝集成。
? ? CXF服务端、、客户端实现WebService服务的方式主要有两点:
? ? ? ?调用原则如下图:
? ? ? ? 首先做两点说明,使用CXF发布一个服务于与Jax-Ws发布一个服务完全不同:
? ? ??OK,废话不多说,直接上代码:
? ? ? 先定义对外发布服务的接口:
class="java">public interface IHelloService { String sayHello(String name); }? ? 然后利用ServerFactoryBean对外发布服务:
/** * 使用ServerFactoryBean发布CXF的Web服务 */ public class HelloService implements IHelloService { /** * 对外发布的方法 * @param name * @return */ public String sayHello(String name) { System.err.println("hello, " + name); return "hello, " + name; } public static void main(String[] args) { ServerFactoryBean bean = new ServerFactoryBean(); // 服务的发布地址 bean.setAddress("http://localhost:9999/sayHello"); // 对外提供服务的类的类型,在面向接口编程时填写接口,否则写实现类 bean.setServiceClass(IHelloService.class); // 对外提供服务的功能实现类 bean.setServiceBean(new HelloService()); // 发布服务 publish()... bean.create(); System.out.println("服务已发布..."); } }? ? 使用CXF发布完此服务后,使用wsimport生成客户端一样可以成功调用此服务。最后废话一句,CXF要依赖的包太多了,当然也是我懒得去区分各个包的作用导致的。在浏览器中输入http://localhost:9999/sayHello?wsdl验证服务是否发布。?
? ? ? 首先获取服务接口,有两种方式,如何可以直接联系服务方拿到定义的接口文件则可以拿过来直接使用,当然也可以利用wsimport获得接口文件来使用(此方法在java RMI一文中有阐述)。这里我就直接把服务端的接口文件直接拿过来用了。
? ? ? 直接上代码:
/** * 使用ClientProxyFactoryBean调用CXF的Web服务(必须是使用ServerFactoryBean方式发布的) */ public class HelloServiceClient { public static void main(String[] args) { ClientProxyFactoryBean bean = new ClientProxyFactoryBean(); // 设置客户端需要使用服务的地址 bean.setAddress("http://localhost:9999/sayHello"); // 创建服务接口对象(接口对象用的仍是服务端的服务接口对象) IHelloService helloService = (IHelloService) bean.create(IHelloService.class); // 使用服务 String result = helloService.sayHello("熊燕子"); System.out.println(result); } }
? ? 当然,客户端既然用的仍然是CXF,那么还是需要导入那么多包的。
? ? ? ?JaxWsServiceFactoryBean是ServerFactoryBean的子类,也是功能扩展类,此类必须要在被发布为服务的类的上添加@WebService注解,如果不加注解,虽然运行不会报错,但是也不会对外暴露任何方法。最重要的一点是,使用此类生成的wsdl文件更加规范。
? ? 先定义服务接口,直接上代码:
@WebService @BindingType(value=SOAPBinding.SOAP12HTTP_BINDING) /** * 通过@BindingType(value=SOAPBinding.SOAP12HTTP_BINDING)转换为实现SOAP1.2 */ public interface IHelloService { public String sayHello(String name); }
? ? 然后发布服务?:
/** * 使用JaxWsServerFactoryBean发布CXF的Web服务 * 注意:需要发布的服务接口必须加入WebService注解,如果不加,虽然不报错,但是所有的方法都暴露不出来 */ public class HelloService implements IHelloService { /** * 对外发布的方法 * @param name * @return */ @Override public String sayHello(String name) { System.err.println("hello, " + name); return "hello, " + name; } public static void main(String[] args) { JaxWsServerFactoryBean bean = new JaxWsServerFactoryBean(); // 设置服务的发布地址 bean.setAddress("http://localhost:9999/sayHello"); // 对外提供服务的类的类型,在面向接口编程时填写接口,否则写实现类 bean.setServiceClass(IHelloService.class); // 对外提供服务的功能实现类 bean.setServiceBean(new HelloService()); // 发布服务 publish()... bean.create(); System.out.println("服务已发布..."); } }? ? ? ??使用CXF发布完此服务后,使用wsimport生成客户端一样可以成功调用此服务。与wsimport类似的还有CXF提供的wsdl2java命令,也同样可以生成客户端代码。此工具位于CXF_HOME/bin目录下,只是参数与wsimport有所不同,它包含以下常用参数:
? ? ? ?用JaxWsServiceFactoryBean发布的服务,在客户端需要使用JaxWsProxyFactoryBean类进行调用,调用过程与前面的过程类似。
? ? ? ?这里还是直接把服务端的服务接口文件IHelloService.javaz直接拷贝到客户端来使用。(当然,wsimport和wsdl2java都可以用来生成功能接口)
/** * 利用JaxWsProxyFactoryBean进行WebService服务调用(只能调用JaxWsServerFactoryBean发布的服务) */ public class HelloServiceClient { public static void main(String[] args) { JaxWsProxyFactoryBean bean = new JaxWsProxyFactoryBean(); // 设置客户端需要使用服务的地址 bean.setAddress("http://localhost:9999/sayHello"); // 设置服务接口的类型 bean.setServiceClass(IHelloService.class); // 创建服务接口对象 IHelloService helloService = (IHelloService) bean.create(); // 调用WebService服务 String ret = helloService.sayHello("aa"); System.out.println(ret); } }
? ? ? ? 利用wsdl2java命令生成客户端调用代码,进行客户端开发。
/** * 通过wsdl2java生成客户端代码调用Webservice服务 */ public class HelloServiceClient { public static void main(String[] args) { // 获取服务类对象 IHelloServiceService helloServiceService = new IHelloServiceService(); // 获取服务类对象的接口 IHelloService helloService = helloServiceService.getIHelloServicePort(); // 调用服务 String result = helloService.sayHello("熊燕子"); System.out.println(result); } }
? ? 可以发现wsdl2java不管是命令还是生成调用客户端代码,都与wsimport非常类似。