开发环境jdk1.7 CXF版本3.1.17
如果使用3.1以上的高版本CXF框架,则需要jdk1.8的支持。
项目采用简单的web项目整合了spring框架,项目启动则对外发布服务,所需要的jar包,点击链接下载
该jar包就是根据maven依赖得到的最精简的jar包
如果是maven项目请参考一下依赖信息
<dependencies>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxws</artifactId>
<version>3.1.17</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http</artifactId>
<version>3.1.17</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http-jetty</artifactId>
<version>3.1.17</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
</dependencies>
项目截图
发布服务
web.xml
增加了CXF框架的Servlet,添加访问地址映射,访问路径需要包含/servcies/才可以访问到WebService服务
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
version="2.5"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<display-name>cxf</display-name>
<servlet>
<description>Apache CXF Endpoint</description>
<display-name>cxf</display-name>
<servlet-name>cxf</servlet-name>
<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>cxf</servlet-name>
<url-pattern>/services/*</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>60</session-timeout>
</session-config>
</web-app>
java类
demo.spring.service包下的Demo,代表服务类。必须在类上加 @WebService注解,才可以发布该类
import javax.jws.WebService;
@WebService
public class Demo {
public String sayDemo(String s){
return s;
}
}
cxf-servlet.xml
这个文件是发布服务的配置文件,id 可以随意起名,implementor 代表要发布服务的类在项目中的全限定类名,按着ctrl+鼠标左键可以跳转到该类上,代表全限定类名没有写错。address 代表要发布服务地址的最后一位以/demo结尾
<?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.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd ">
<import resource="classpath:META-INF/cxf/cxf.xml" />
<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
<jaxws:endpoint id="demo" implementor="demo.spring.service.Demo"
address="/demo" />
</beans>
到这里可以发布服务,访问地址 http://localhost:8080/cxf_web/services/demo?wsdl
如果访问页面不报错,则代表发布服务成功。
客户端调用
拿到根据服务地址产生的接口文件
在磁盘任意位置新建一个文件夹,在文件夹内按shift+鼠标右键,在此处打开命令窗口。
在窗口内输入命令 : wsimport -s . http://localhost:8080/cxf_web/services/demo?wsdl
即可解析生成java接口文件。根据地址的 portType类型,拿到同名的接口文件,放到项目中。
首先改包名,然后删除报错的地方即可。
demo.spring.interfaces 包下的Demo 即为接口产生的文件。
client-beans.xml
这个文件代表客户端调用的配置文件。
第一个bean id 随便起,获取类要用到。class代表产生接口的类在项目中的全限定类名,factory-bean
代表 引用名。在下面的bean id中引用。factory-method="create" 固定值。
第二个bean id 为 factory-bean的值。class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean" 固定值。
<property name="serviceClass" value="demo.spring.interfaces.Demo" />
<property name="address" value="http://localhost:8080/cxf_web/services/demo" />
红色部分为变动的。第一个value 代表接口的类在项目中的全限定类名。第二个value 代表该类发布地址的WebServcie
格式为:http://部署地址ip:发布服务端口/项目名/services/发布服务地址配置的最后一位(address)。
<?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.xsd
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">
<bean id="demo" class="demo.spring.interfaces.Demo" factory-bean="demoFactory"
factory-method="create" />
<bean id="demoFactory" class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean">
<property name="serviceClass" value="demo.spring.interfaces.Demo" />
<property name="address" value="http://localhost:8080/cxf_web/services/demo" />
</bean>
</beans>
调用服务
demo.spring.client 包下的Client 代表调用服务类。
import org.springframework.context.support.ClassPathXmlApplicationContext;
import demo.spring.interfaces.Demo;
public class Client {
public static void main(String args[]) throws Exception {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
new String[] { "client-beans.xml" });
Demo bean = (Demo) context.getBean("demo");
String sayDemo = bean.sayDemo("abc");
System.out.println(sayDemo);
context.close();
System.exit(0);
}
}
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
new String[] { "client-beans.xml" });
代表spring加载配置文件,产生对象。红色的就是项目中配置文件名称。
context.getBean("demo"); demo就是客户端配置文件的bean id。强制转换为 自动生成的Demo文件,不要用自己写的。
在调用之前先启动服务,可以访问到webservice服务。再用客户端调用,如果能够输出输入的值,代表客户端调用成功。
到这里发布服务,调用服务就完成了。运用cxf框架优势在于客户端只需要服务端产生的接口文件就可以完成调用。
思考
一般的项目都是web项目,启动项目即可发布服务。本案例中发布服务就是这样。
但是,客户端调用是main方法启动,不友好。应该客户端启动就可以拿到spring创建的对象,直接使用对象调用方法。
解决方案
1.采用单例模式,让配置文件只加载一次
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class SingletonContext {
private SingletonContext() {
} // 私有构造函数
private volatile static ClassPathXmlApplicationContext Context = null; // 单例对象
public static ClassPathXmlApplicationContext getContext() {
if (Context == null) {
synchronized (SingletonContext.class) { // 同步锁
if (Context == null) { // 双重检测机制
Context = new ClassPathXmlApplicationContext(new String[] { "client-beans.xml" });
}
}
}
return Context;
}
}
2.. 项目启动让spring加载客户端配置的文件,产生对象。然后在项目中@AutoWired 注入使用。
注意web.xml配置 spring监听器,指定监听客户端配置文件
client-beans.xmll 配置spring 包扫描,扫描指定接口文件。注意添加spring context名称空间约束
项目中引用
@Autowired
private Demo demo;