XFire 是与Axis 2并列的新一代Web Service框架,通过提供简单的API支持Web Service各项标准协议,能够快速地开发Web Service应用。和其他Web服务引擎相比,XFire的配置非常简单,可以非常容易地和Spring集成。
以下以一个Demo程序为例讲解如何编写一个Xfire的服务端与客户端:
xfire版本:xfire-distribution-1.2.6.zip
目录结构:
关键代码:
User.javapackage com.alfred.xfire.bean; public class User { private String id; private String name; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
IHelloService.javapackage com.alfred.xfire.service; import com.alfred.xfire.bean.User; public interface IHelloService { public String sayHello(String name); public User getUser(User user); }
HelloService.javapackage com.alfred.xfire.service; import com.alfred.xfire.bean.User; public class HelloService implements IHelloService { public String sayHello(String name) { return "Hello, " + name; } public User getUser(User user) { User userNew = new User(); userNew.setId("next" + user.getId()); userNew.setName("next" + user.getName()); return userNew; } }
ClientTest.javapackage com.alfred.xfire.client; import java.net.MalformedURLException; import java.net.URL; import org.codehaus.xfire.XFire; import org.codehaus.xfire.XFireFactory; import org.codehaus.xfire.client.Client; import org.codehaus.xfire.client.XFireProxyFactory; import org.codehaus.xfire.service.Service; import org.codehaus.xfire.service.binding.ObjectServiceFactory; import com.alfred.xfire.bean.User; import com.alfred.xfire.service.IHelloService; public class ClientTest { public static void main(String[] args) { // visitMethod01(); visitMethod02(); } private static void visitMethod01() { try { Client client = new Client( new URL( "http://127.0.0.1:8080/XfireDemo/services/HelloService?wsdl")); Object[] results = client.invoke("sayHello", new Object[] { "alfred" }); System.out.println(results[0].toString()); } catch (MalformedURLException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } private static void visitMethod02() { // Create a metadata of the service 创建一个service的元数据 Service srvcModel = new ObjectServiceFactory() .create(IHelloService.class); // Create a proxy for the deployed service 为XFire获得一个代理工厂那个对象 XFire xfire = XFireFactory.newInstance().getXFire(); XFireProxyFactory factory = new XFireProxyFactory(xfire); String url = "http://127.0.0.1:8080/XfireDemo/services/HelloService"; try { IHelloService helloService = (IHelloService) factory.create( srvcModel, url); User user = new User(); user.setId("userid"); user.setName("alfred"); User newUser = helloService.getUser(user); System.out.println("id:" + newUser.getId()); System.out.println("name:" + newUser.getName()); } catch (Exception e) { e.printStackTrace(); } } }
services.xml<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://xfire.codehaus.org/config/1.0"> <service> <name>HelloService</name> <namespace>com.alfred.xfire.service</namespace> <serviceClass>com.alfred.xfire.service.IHelloService</serviceClass> <implementationClass>com.alfred.xfire.service.HelloService</implementationClass> </service> </beans>
web.xml<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"> <servlet> <servlet-name>XFireServlet</servlet-name> <servlet-class> org.codehaus.xfire.transport.http.XFireConfigurableServlet </servlet-class> </servlet> <servlet-mapping> <servlet-name>XFireServlet</servlet-name> <url-pattern>/servlet/XFireServlet/*</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>XFireServlet</servlet-name> <url-pattern>/services/*</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app>
导入jar包:
将xfire-all-1.2.6.jar以及lib目录下的jar包全部导入即可。
services.xml文件默认的存放目录是WEB-INF/META-INF/xfire下或WEB-INF/classes/META-INF/xfire下,如果是后者,那么实际项目中META-INF应放置于src目录下:
这样,部署到服务器中后META-INF文件夹就会存在于WEB-INF/classes/目录下。如果要自己指定services.xml文件路径,可以将services.xml路径配置在web.xml文件中,如下:
<servlet> <servlet-name>XFireServlet</servlet-name> <servlet-class> org.codehaus.xfire.transport.http.XFireConfigurableServlet </servlet-class> <!-- The servlet will by default look for the configuration on the classpath in "META-INF/xfire/services.xml". You can override it with this parameter. Seperate multiple configuration files with a comma. --> <!-- 默认会在classpath的META-INF/xfire/下查找services.xml文件, 可以覆盖这个参数,指定多个配置文件--> <init-param> <param-name>config</param-name> <param-value>xfire-services.xml</param-value> </init-param> </servlet>
插入一段init-param配置,param-name为config,指定services.xml文件的路径以及文件名。
配置后目录结构如下:
客户端调用
xfire的客户端有三种调用方式:
1、直接通过url调用, 不用客户端提供接口类
private static void visitMethod01() { try { Client client = new Client( new URL( "http://127.0.0.1:8080/XfireDemo/services/HelloService?wsdl")); Object[] results = client.invoke("sayHello", new Object[] { "alfred" }); System.out.println(results[0].toString()); } catch (MalformedURLException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } }
2、通过服务端提供的接口类进行调用
private static void visitMethod02() { // Create a metadata of the service 创建一个service的元数据 Service srvcModel = new ObjectServiceFactory() .create(IHelloService.class); // Create a proxy for the deployed service 为XFire获得一个代理工厂那个对象 XFire xfire = XFireFactory.newInstance().getXFire(); XFireProxyFactory factory = new XFireProxyFactory(xfire); String url = "http://127.0.0.1:8080/XfireDemo/services/HelloService"; try { IHelloService helloService = (IHelloService) factory.create( srvcModel, url); User user = new User(); user.setId("userid"); user.setName("alfred"); User newUser = helloService.getUser(user); System.out.println("id:" + newUser.getId()); System.out.println("name:" + newUser.getName()); } catch (Exception e) { e.printStackTrace(); } }
3、通过服务端的WSDL反向生成客户端,很多IDE或者使用Ant都可以反向生成客户端,这里就不复诉了
三种客户端比较:
第一种方式是最为简便的,只需要URL就可以访问到,但是在效率上要低于另外两种方式。如果在可以得到服务端提供的接口类的情况下,最好的方法是使用第二种方式调用,效率最高。第三种方式其实和第二种有些类似(但估计没有第二种效率高,毕竟反向生成,可能会加入很多适用性的代码)。另外,就传递和返回数据来说,第一种方式只能传递基本数据类型或String等,无法传递接收自定义对象,后两种方式可以,当然,如果想要用第一种方式传递自定义对象可以先通过xstream等工具将其转换为XML字符串,然后传递解析,就可以了。
源码解析
org.codehaus.xfire.transport.http.XFireConfigurableServlet文件中,载入services.xml的相关代码如下:
private final static String CONFIG_FILE = "META-INF/xfire/services.xml"; private final static String PARAM_CONFIG="config"; /** * Path to configuration file */ private String configPath; /** * @return */ private String getConfigPath() { if (configPath == null || configPath.length() == 0) { return CONFIG_FILE; } return configPath; } public XFire createXFire() throws ServletException { configPath = getInitParameter(PARAM_CONFIG); XFire xfire; try { xfire = loadConfig(getConfigPath()); } catch (XFireException e) { throw new ServletException(e); } if(xfire == null || xfire.getServiceRegistry() == null || xfire.getServiceRegistry().getServices() == null || xfire.getServiceRegistry().getServices().size() == 0) { xfire = super.createXFire(); } return xfire; }
可以看到默认的service.xml加载路径为:
private final static String CONFIG_FILE = "META-INF/xfire/services.xml";
当创建xfire时会去加载configPath:
configPath = getInitParameter(PARAM_CONFIG); private final static String PARAM_CONFIG="config";
如果此时没有设置config参数那么就会取用默认services.xml路径配置:
private String getConfigPath() { if (configPath == null || configPath.length() == 0) { return CONFIG_FILE; } return configPath; }
由此可见我们可以在web.xml里修改config参数进行路径配置。