一,BUS提供全局拦截器功能
下面来举例子说明,如何为所有的endpoint提供日志拦截:
<bean id="logOutbound" class="org.apache.cxf.interceptor.LoggingOutInterceptor"/>
<cxf:bus>
<cxf:outInterceptors>
<ref bean="logOutbound"/>
</cxf:outInterceptors>
</cxf:bus>
上面提供了拦截所有出去的消息日志。可以提供的拦截点包括:
Name | Value |
---|---|
inInterceptors | 拦截接收到的消息 |
inFaultInterceptors | 拦截接收错误消息 |
outInterceptors | 拦截发出去的消息 |
outFaultInterceptors | l拦截发出去的错误消息 |
这个拦截器与各endpoint的拦截器一样,需要实现Interceptor接口。这些拦截器都是作用于全局的。
二、CXF bus提供了一些feature。通过配置即可激活这些功能。
举例来说,bus有一个logging的feature。能够拦截所有的进入、发出以及错误的消息。呵呵,不需要配置拦截器咯,激活这个功能即可。实现这个功能的是org.apache.cxf.feature.LoggingFeature类。下面举例说明如何激活这个feature:
<cxf:bus>
<cxf:features>
<cxf:logging/>
</cxf:features>
</cxf:bus>
比较简单,这样就可以输出日志了。它还提供了其他的一些feature,可以参考:
http://cxf.apache.org/docs/featureslist.html。用到的话可以查询下了。具体用法参考上面的例子即可。大概提供的feature涵盖了故障转移、加解密消息、压缩解压消息,ws-address支持,ws-policy支持以及轻量级消息转发。
当然,你也可以扩展自己的featrue,只需要继承AbstractFeature并实现initializeProvider 这个方法即可。这个方法提供了修改InterceptorProvider 的机会。查看InterceptorProvider 接口即知道,这个接口提供了访问上面提到的四个拦截的入口。
public interface InterceptorProvider {
List<Interceptor> getInInterceptors();
List<Interceptor> getOutInterceptors();
List<Interceptor> getInFaultInterceptors();
List<Interceptor> getOutFaultInterceptors();
}
三、CXF bus还管理了扩展插件(extension)
比如 DestinationFactoryManager 可以在运行时从extension中获取,
Bus bus = BusFactory.getThreadDefaultBus();
DestinationFactoryManagerImpl dfm = bus.getExtension(DestinationFactoryManagerImpl.class);
类似的还有BindingFactoryManager.ConduitInitiatorManager等。这些是专用位置哦。一般,这些可用对象可以从classpath以下路径看到:
META-INF/cxf/cxf.xml (e.g., in cxf-rt-core only)
META-INF/cxf/cxf-extension.xml (e.g. in cxf-rt-bindings-soap)
META-INF/cxf/cxf-property-editors.xml (e.g. in cxf-rt-transports-http)
例如:可以从cxf-rt-core-****.jar包中的META-INF/cxf/cxf-extension.xml 文件中,看到以下已经注入的对象org.apache.cxf.wsdl11.WSDLManagerImpl,org.apache.cxf.phase.PhaseManagerImpl等等。
当然,你可以自定义extension。并且在自己的jar包的META-INF/cxf/cxf-extension.xml这个路径中,配置你自己的bean。这个bean是一个POJO的bean,不需要实现任何依赖于cxf的接口。当然,你也可以扩展cxf已有的功能。配置完成后,你可以在运行时bus.getExtension(your.class);来获取你的扩展啦。
我觉得这个设计虽然灵活,但设计的过于灵活啦,只是简单的把这些可用的bean放入一个map里面,以供查询使用。违背了面向对象的设计原则。我相信很多读者到这都会感觉,这个扩展可以扩展的东西其实是无限的,但刚开始却会让你无从下手。
这里有几个和Bus创建相关的类
BusFactory
定义了创建Bus的基本方法,它是一个抽象类。这里需要注意的{get|set}DefaultBus这两个方法。了解JAXWS API的朋友可能会有这样的疑问,就是JAXWS API中没有Bus这一概念,如果CXF要实现JAXWS API
接口怎么引入Bus这一对象呢?CXF在实现JAXWS API过程中,通过调用BusFactory.getDefaultBus()来设置内部模块使用的Bus。getDefaultBus会检测静态变量defaultBus赋值情况来决定是否要创建新的Bus。 在这我们就引出了在CXF中如果要使用JAXWS API来创建服务的话,我们可以预先配置好Bus,然后通过调用BusFactory.setDefaultBus(),来设置CXF 在实现JAWS API中使用的Bus。
具体的例子大家可以参看AbstractJaxWsTest中的setUpBus()。在这里我们没有使用到HTTPTransport来进行UnitTest,而是使用一个简单LocalTransport来测试Client Server之间的通讯,其中奥妙大家可以慢慢体会。
CXFBusImpl
是Bus接口的具体实现。这里大家可以看看如何实现{get|set}Extension。
ExtensionManagerBus
是Bus接口的另一个实现。这个Bus通过读取Class Path 中的META-INF/bus-extensions.xml文件来获取扩展模块的信息。
在ExtensionManagerBus中的初始化代码中,你可以发现CXF core中所必须的Managers(Bus也算是一个Manager集中营)。其中有负责获取资源管理的ResourceManager,负责扩展模块管理的ExtensionManger,负责Bus生命周期管理的BusLifeCycleManager, 负责初始化Server端Transport的DestionationFactoryManager, 复杂初始化Client端Transport的ConduitInitiatorManager, 负责初始化Binding的BindingFactoryManager。
这里是SoapBinding bus-extension.xml的例子。
CXFBusFactory
继承了BusFactory,并通过ExtensionManagerBus来负责加载CXF的扩展模块。
SpringBusFactory
通过SpringApplicationContext来加载CXF扩展模块。SpringBusFactory是缺省的BusFactory。这里需要说明的是SpringBusFactory需要配合Spring来使用,如果Class Path中没有包含Spring jars,那CXF Core会使用CXFBusFactory来加载扩展模块。随着Spring的大量普及,相信大家会大量使用SpringBusFactory来创建Bus。
在SpringBusFactory中,初始化的Bus实例是CXFBusImpl。但是如果你搜索一下SpringBusFactory以及CXFBusImpl的代码,是不会发现类似与ExtensionManagerBus那样的初始化代码的。 这是为什么呢?
当当当, 这是就是Spring的强大Wire功能,相关的Manager初始化代码转变成为了CXF.xml。有意思吧!