Apache CXF实现Web Service(5)—— GZIP使用
Apache CXF实现Web Service(5)—— GZIP使用
参考来源:
- CXF WebService整合Spring
- Apache CXF实现Web Service(1)——不借助重量级Web容器和Spring实现一个纯的JAX-WS web service
- Apache CXF实现Web Service(4)——Tomcat容器和Spring实现JAX-RS(RESTful) web service
首先参照
Apache CXF实现Web Service(4) 创建一个WTP项目,并参照(1) 新建一个测试的Web Service:HelloWorld.java和其实现HelloWorldImpl.java
HelloWorld.java
package com.cnblog.richaaaard.cxftest.spring.ws.helloworld.services;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
import org.apache.cxf.annotations.GZIP;
//@GZIP(threshold=128)
@GZIP
@WebService
public interface HelloWorld {
@WebMethod
@WebResult String sayHi(@WebParam String text);
}
HelloWorldImpl.java
package com.cnblog.richaaaard.cxftest.spring.ws.helloworld.services;
import javax.jws.WebService;
@WebService(endpointInterface="com.cnblog.richaaaard.cxftest.spring.ws.helloworld.services.HelloWorld",serviceName="helloService")
public class HelloWorldImpl implements HelloWorld {
public String sayHi(String name) {
String msg = "Hello " + name + "!";
return msg;
}
}
在Spring的配置中需要注意的是,我们需要引入jarws的schema
http://cxf.apache.org/jaxws
http://cxf.apache.org/schemas/jaxws.xsd
完整的配置文件如下:
<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-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd"
default-lazy-init="true">
<import resource="classpath:META-INF/cxf/cxf.xml"/>
<import resource="classpath:META-INF/cxf/cxf-servlet.xml"/>
<bean id="helloService" class="com.cnblog.richaaaard.cxftest.spring.ws.helloworld.services.HelloWorldImpl">
</bean>
<jaxws:endpoint implementor="#helloService" address="/HelloService"/>
</beans>
web.xml文件保持不变
<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-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd"
default-lazy-init="true">
<import resource="classpath:META-INF/cxf/cxf.xml"/>
<import resource="classpath:META-INF/cxf/cxf-servlet.xml"/>
<bean id="helloService" class="com.cnblog.richaaaard.cxftest.spring.ws.helloworld.services.HelloWorldImpl">
</bean>
<jaxws:endpoint implementor="#helloService" address="/HelloService"/>
</beans>
项目结构如图
下面需要测试几个问题
- @GZIP如何工作的?
- @GZIP有两个属性 force 和 threshold 怎么用?
- @GZIP加在接口上是否可行?(我们用Spring实例化bean是用的HelloWorldImpl)
测试
@GZIP如何工作的?
第一步
在Eclipse中Run As... -> Run on Server,然后在浏览器中验证是否发布成功:
我们Tomcat本地运行的端口是8080。
第二步
运行TCPMon,新建监听端口8081,目标端口8080:
第三步
新建客户端测试代码,并将address设置成"http://localhost:8081/cxf/services/HelloService"
package com.cnblog.richaaaard.cxftest.spring.ws.helloworld.client;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import org.apache.cxf.transport.common.gzip.GZIPInInterceptor;
import org.apache.cxf.transport.common.gzip.GZIPOutInterceptor;
import com.cnblog.richaaaard.cxftest.spring.ws.helloworld.services.HelloWorld;
public class Client {
public static void main(String[] args) {
JaxWsProxyFactoryBean client = new JaxWsProxyFactoryBean();
// factory.getInInterceptors().add(new LoggingInInterceptor());
// factory.getOutInterceptors().add(new LoggingOutInterceptor());
// factory.getInInterceptors().add(new GZIPInInterceptor());
// factory.getOutInterceptors().add(new GZIPOutInterceptor());
client.setServiceClass(HelloWorld.class);
client.setAddress("http://localhost:8081/cxf/services/HelloService");
HelloWorld helloworld = (HelloWorld) client.create();
System.out.println(helloworld.sayHi("Richard"));
System.exit(0);
}
}
第一个测试,运行Client.java
Run As... -> Java Application
在TCPMon(关于如何使用TCPMon请查看http://www.cnblogs.com/richaaaard/p/5019438.html)中查看结果
发现并没有像预料中的那样发生GZIP压缩
怀疑出现问题
- 服务器不支持GZIP?
- CXF有BUG?
- 使用方式有问题?
打开@GZIP Annotation的源码查看
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE })
@Inherited
public @interface GZIP {
int threshold() default -1;
boolean force() default false;
}
这个标注有两个属性:threshold 与 force
然后查看Apache CXF 关于@GZIP的文档 (CXF Features http://cxf.apache.org/docs/featureslist.html) 与 (CXF Annotations http://cxf.apache.org/docs/annotations.html)
细心的同学会发现“CXF Features文档中关于GZIPFeature的说明中仍然出现了FastInfoset”这个错误
- threshold - the threshold under which messages are not gzipped
- force - force GZIP compression instead of negotiating via the Accept-Encoding header
GZIP is a negotiated enhancement. An initial request from a client will not be gzipped, but an Accept header will be added and if the server supports it, the response will be gzipped and any subsequent requests will be.
上面一段话的意思是:第一次请求不会发生GZIP,但是如果服务器支持,会加如到Accept头上,返回的消息会发生GZIP然后,后面发生的请求也会有GZIP。
关于threshold的定义:可以发现我们测试中的请求(request)长度(Content-Length)是232,返回(response)长度是259。
这里猜想
@GZIP应该有一个自己的默认threshold,如果修改默认实现,也就能发生GZIP了
我们将threshold修改成256介于232和259之间
@GZIP(threshold=256)
//@GZIP
@WebService
public interface HelloWorld {
@WebMethod
@WebResult String sayHi(@WebParam String text);
}
重启服务器,运行程序
请求没有发生GZIP,而响应端有GZIP
再次运行Client(不重启服务器)
我们发现,请求(request)并没有像Apache官方文档那样说的,也会有GZIP。
这是为什么呢?是不是和我们的客户端有关?
将代码增加一次请求试试
发现连续的两次请求仍然没有发生GZIP。再仔细查看关于GZIP的解释,"...如果服务器支持..."
package com.cnblog.richaaaard.cxftest.spring.ws.helloworld.client;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import org.apache.cxf.transport.common.gzip.GZIPInInterceptor;
import org.apache.cxf.transport.common.gzip.GZIPOutInterceptor;
import com.cnblog.richaaaard.cxftest.spring.ws.helloworld.services.HelloWorld;
public class Client {
public static void main(String[] args) {
JaxWsProxyFactoryBean client = new JaxWsProxyFactoryBean();
// factory.getInInterceptors().add(new LoggingInInterceptor());
// factory.getOutInterceptors().add(new LoggingOutInterceptor());
// factory.getInInterceptors().add(new GZIPInInterceptor());
// factory.getOutInterceptors().add(new GZIPOutInterceptor());
client.setServiceClass(HelloWorld.class);
client.setAddress("http://localhost:8081/cxf/services/HelloService");
HelloWorld helloworld = (HelloWorld) client.create();
System.out.println(helloworld.sayHi("Richard"));
System.out.println(helloworld.sayHi("Kobe Bryant"));
System.exit(0);
}
}
这里猜想
是不是我们服务器的设置问题,不支持GZIP呢?
修改Tomcat的Connector配置,增加
compressionMinSize="256"
compression="on"
noCompressionUserAgents="gozilla, traviata"
compressableMimeType="text/html,text/xml"
然后重启服务器,再运行客户端
发现请求(request)仍然没有发生GZIP
如何才能使请求也提交GZIP格式呢?
我们暂且放下这个问题,先将Tomcat配置文件关于compression的配置还原
来看看force如何工作的
在HelloWorld.java的头上修改@GZIP增加force属性,threshold仍然为256
@GZIP(force=true, threshold=256)
@WebService
public interface HelloWorld {
@WebMethod
@WebResult String sayHi(@WebParam String text);
}
请求仍然没有被压缩
![](http://images2015.cnblogs.com/blog/613455/201512/613455-20151204175354393-824266017.png
修改成128呢?因为请求的Content-Length是232
在次运行,发现请求成功压缩了(这是请求压缩的一种情景)
好像漏了什么东西
之前我们反复测试,期望第二次请求(request)可以根据服务端返回的Accept-Encoding header 自行进行GZIP压缩,我们测试代码当时设置的threhold是256,而请求的Content-Length=232。我们将threshold调整到128,去掉force属性,重启服务器再试一下(这时的Tomcat没有配置compression相关属性)。
- 当我们单次运行的时候(每次客户端运行结束,进程退出)
先后运行两次独立的请求,请求(request)没有发生GZIP,这是因为客户端是不同进程的缘故
- 当我加入一行代码,在统一进程中连续两次请求服务器时,我们会发现第二次请求会自行GZIP压缩,而此时Tomcat上没有对compression进行特别配置
由此可见
Tomcat是内置支持GZIP的服务器
Tomcat上的compression是服务器自己独立的压缩机制,与Apache CXF无关,但是服务器级别的配置会影响我们使用的CXF Web Service
那么问题来了
Tomcat服务器配置的压缩机制是怎么工作的呢?
*扩展
StackOverflow上关于GZIPInInterceptor和GZIPOutInterceptor的回答是否正确?
通过上面的所有测试就能得出结论,这个Interceptor并不对服务端响应消息的GZIP起任何作用,读者可以自行测试
Apache CXF实现Web Service(5)—— GZIP使用的更多相关文章
- Apache CXF实现Web Service(4)——Tomcat容器和Spring实现JAX-RS(RESTful) web service
准备 我们仍然使用 Apache CXF实现Web Service(2)——不借助重量级Web容器和Spring实现一个纯的JAX-RS(RESTful) web service 中的代码作为基础,并 ...
- Apache CXF实现Web Service(3)——Tomcat容器和不借助Spring的普通Servlet实现JAX-RS(RESTful) web service
起步 参照这一系列的另外一篇文章: Apache CXF实现Web Service(2)——不借助重量级Web容器和Spring实现一个纯的JAX-RS(RESTful) web service 首先 ...
- Apache CXF实现Web Service(2)——不借助重量级Web容器和Spring实现一个纯的JAX-RS(RESTful) web service
实现目标 http://localhost:9000/rs/roomservice 为入口, http://localhost:9000/rs/roomservice/room为房间列表, http: ...
- Apache CXF实现Web Service(1)——不借助重量级Web容器和Spring实现一个纯的JAX-WS web service
废话少说,先在Eclipse中新建一个Java Project (可以不是WTP的Dynamic Web Project) 选择Java Project 再看pom.xml 我们使用cxf 3.1.4 ...
- 基于Apache CXF的Web Service服务端/客户端
转自:https://www.aliyun.com/zixun/wenji/1263190.html CXF服务端: package com.sean.server; import javax.jws ...
- Web Service学习-CXF开发Web Service实例demo(一)
Web Service是什么? Web Service不是框架.更甚至不是一种技术. 而是一种跨平台,跨语言的规范 Web Service解决什么问题: 为了解决不同平台,不同语言所编写的应用之间怎样 ...
- 使用CXF开发Web Service服务
1.使用CXF开发Web Service服务端 1.1 开发一个Web Service业务接口,该接口要用@WebService修饰 (1)创建一个Java项目MyServer (2)在MyServe ...
- Web Service学习-CXF开发Web Service的权限控制(二)
Web Service怎样进行权限控制? 解决思路:server端要求input消息总是携带实username.password信息,假设没实username和password信息.直接拒绝调用 解决 ...
- 应用Apache Axis进行Web Service开发
转自(http://tscjsj.blog.51cto.com/412451/84813) 一.概述 SOAP原意为Simple Object Access Protocol(简单对象访问协议),是一 ...
随机推荐
- JavaWeb之 JSP:内置对象,EL表达式,JSP标签基础
JSP的内置对象 什么是JSP的内置对象呢? 在JSP页面进行编程的时候,如果我们要使用一些对象,如:HttpSession,ServletConfig,ServletContext这些对象,如果每次 ...
- Kettle计算器的使用以及字符串格式化
1.简介 先生成随机数,将生成的2列随机数进行计算,并且格式化计算结果 2.kettle流程图 3.流程图详细描述 3.1生成随机数 生成2个随机数字,列名为N1,N2 3.2计算器 将N1与N2对应 ...
- PHP 文件操作函数大全
<?php 读取文件夹: $handler = opendir("c:\");//打开文件夹 while($dir = readdir($handler)){//遍历文件夹 ...
- hdu 2034 人见人爱A-B
题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=2034 人见人爱A-B Description 参加过上个月月赛的同学一定还记得其中的一个最简单的题目, ...
- core java 1~4(HelloWorld & 标识符|关键字|数据类型 & 表达式|流程控制 & 数组)
MODULE 1 Java的编译和运行----------------------------编译:javac -d bin src\HelloWorld.java -d:指定编译后的class 文件 ...
- iOS学习之Object-C语言内存管理高级
一.属性的内存管理
- iOS七大手势之(平移、捏合、轻扫、屏幕边缘轻扫)手势识别器方法
使用手势很简单,分为两步: 创建手势实例.当创建手势时,指定一个回调方法,当手势开始,改变.或结束时,回调方法被调用. 添加到需要识别的View中.每个手势只对应一个View,当屏幕触摸在View的边 ...
- extjs 表格可复制
在GridPanel的配置项中,加入这个配置就可以了: viewConfig:{ enableTextSelection:true }
- [超简洁]EasyQ框架-应对WEB高并发业务(秒杀、抽奖)等业务
背景介绍 这几年一直在摸索一种框架,足够简单,又能应付很多高并发高性能的需求.研究过一些框架思想如DDD DCI,也实践过CQRS框架. 但是总觉得复杂度高,门槛也高,自己学都吃力,如果团队新人更难接 ...
- FPGA内部信号避免高阻态
RT,否则警告Warning: Tri-state node(s) do not directly drive top-level pin(s),会利用或门代替中间的扇出fan-out. 原因:在进行 ...