需要实现一个功能,即记录每次webservice服务调用的一些参数,比如调用时间,执行时间等。原来的产品是使用axis开发的,接到这个功能的时候便想着采用Spring AOP结合CXF的方式来实现,于是开始准备一个Demo。
@WebService
@SOAPBinding(style = Style.DOCUMENT)
public interface HelloWorld {
public String sayHello(@WebParam(name = "name") String name);
}
public class HelloWorldImpl implements HelloWorld {
@Override
public String sayHello(String name) {
return name + " Say:hello world~!!!!!!!!!!!!!";
}
}
定义接口,定义实现类,然后配置Spring容器
<bean id="helloWorldImpl"
class="com.smart.service.testcxf.HelloWorldImpl" />
<jaxws:endpoint id="helloWorldService"
implementor="#helloWorldImpl" address="/helloWorld">
<jaxws:properties>
<entry key="mtom-enabled" value="true" />
</jaxws:properties>
</jaxws:endpoint>
启动服务,客户端采用C#,根据WSDL生成对应的服务代理类,调用服务,直接报错,application/xop+xml等等。
好吧,辛辛苦苦查资料,终于解决,消息编码问题,只需修改配置的编码方式为“Mtom”就能解决问题。
<configuration>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding messageEncoding="Mtom">
</binding>
</basicHttpBinding>
</bindings>
</system.serviceModel>
</configuration>
百度资料之后,貌似客户端是.NET的就会有这个问题,JAVA的不存在这个问题。
解决之后满心欢喜,基于@AspectJ定义切面,增强类型为环绕增强,代码准备完毕之后,满心欢喜,先利用Junit测试一下,结果如下
哈哈,没问题,那就直接跑服务来测试,服务端日志打印也是正常的,但是客户端就很尴尬了
没有数据返回!!!想想可能的原因是服务类被代理了,新生成的代理类没有@WebService的注解,所以导致服务数据返回失败。
最终百度了下,说重写AbstractJaxWsServiceExporter和SimpleHttpServerJaxWsServiceExporter这两个类,在加载的时候自己处理获取原型类和对象,该层的切面交给Authenticator处理。这样能实现功能。
但是本人能力有限,折腾了一阵还是没能成功,希望哪位大佬给予指点,助小弟实现该功能,感激不尽噢。
没办法,最终转而使用CXF拦截器
<!-- 单个拦截器 -->
<bean id="inMessageInterceptor" class="org.apache.cxf.interceptor.LoggingInInterceptor" />
<bean id="outMessageInterceptor" class="org.apache.cxf.interceptor.LoggingOutInterceptor"/>
<bean id="myInInterceptor" class="com.smart.interceptor.MyInInterceptor"/>
<!-- 输入日志拦截器 -->
<jaxws:inInterceptors>
<ref bean="inMessageInterceptor"/>
<ref bean="myInInterceptor"/>
</jaxws:inInterceptors>
<!-- 输出日志拦截器 -->
<jaxws:outInterceptors>
<ref bean="outMessageInterceptor"/>
</jaxws:outInterceptors>
此处myInInterceptor为自定义的In拦截器,
其中Phase.PRE_INVOKE在构造函数中声明,表示拦截器在哪个阶段起作用。重写handleMessage方法,这里做我们需要做的处理。
另外,因为调取webservice服务是异步的,所以实际拦截过程中,我们并不知道哪次OUT拦截对应IN拦截,这里我们需要做点处理。
在服务端IN拦截器中,添加如下代码
message.getExchange().put("CXF", "test");
在服务端OUT拦截器中,添加如下代码:
message.getExchange().get("CXF");
这里“CXF”作为key值,“test”作为value值,经过测试,同一次服务的IN message.getExchange()与OUT message.getExchange()相同的key得到的value值相同。