【问题标题】:Create new CXF Bus via API通过 API 创建新的 CXF 总线
【发布时间】:2016-09-04 03:31:00
【问题描述】:

我正在尝试将 Apache CXF 与 OSGI enRoute 一起使用。不同的是,我不想使用 cfg.xml 文件,而是通过 API 启动我的服务端点。下面就是这样一个例子:

    InvolvedPartySoap12EndpointImpl involvedPartyServiceImpl = new InvolvedPartySoap12EndpointImpl();
    ServerFactoryBean svrFactory = new JaxWsServerFactoryBean();
    svrFactory.setServiceClass(InvolvedPartyPortType.class);
    svrFactory.setAddress("/bin/InvolvedParty");
    svrFactory.setBus(bus);
    svrFactory.setServiceBean(involvedPartyServiceImpl);
    _server = svrFactory.create();

我遇到的问题是为每个 OSGI 包创建一个不同的 CXF 总线,从而允许我在每次激活/停用相应的包时创建/销毁总线。复制以下 Karaf 命令也是一个目标:

https://access.redhat.com/documentation/en-US/Red_Hat_JBoss_Fuse/6.2/html/API_Reference/files/cxf/org/apache/cxf/karaf/commands/CXFController.html

问题是我没有看到用于创建和销毁 CXF 总线的 API。而且上面列出的 Karaf 代码似乎不适用于 enRoute。

我想可以在包中创建一个 cfg.xml 文件来创建总线,但是我没有看到用于获取具有给定别名的总线的 API。呃。

以下链接看起来很有希望,但是当适应 CXFNonSpringServlet 的子类时...我没有得到相应的 CXF 总线,我似乎也无法通过 API 创建一个:

registering servlet in OSGi that receives parameters

所以我的问题是……有没有人通过 OSGI 中的 API 成功地获取、创建和销毁 CXF 总线(和相应的 servlet)?

谢谢, 兰迪

【问题讨论】:

    标签: osgi cxf


    【解决方案1】:

    CXFNonSpringServlet 源代码显示此 servlet 子类根据需要创建 CXF 总线。所以我采取的方法是简单地创建一个 CXFNonSpringServlet 类的实例,并使用所需的别名向 HTTPService 注册它。

    问题是无法在 BundleActivator 类中调用以下代码,因为无法保证注册 servlet 所需的 HTTPService 在捆绑激活时存在。为此,我创建了一个带有 HTTPService 引用的组件,并在组件激活期间注册了 servlet。我进一步将该组件设置为“即时组件”,以确保在启动期间进行服务注册。

    @Component(immediate = true)
    public class SoapBootstrap
    {
        private static final long serialVersionUID = 1L;
        private static final String Alias = "/party";
    
        private HttpService _httpService;
        private CXFNonSpringServlet _servlet;
    
        @Reference
        public void setHttpService(HttpService theHttpService)
        {
            try {
                _httpService = theHttpService;
                _servlet = new CXFNonSpringServlet();
                _httpService.registerServlet(Alias, _servlet, null, null);
                registerEndpoints();
            } catch (NamespaceException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (ServletException e) {
                e.printStackTrace();
            }
        }
    
        private void registerEndpoints()
        {
            try {
                XyzSoap12EndpointImpl xyzServiceImpl = new XyzSoap12EndpointImpl();
                ServerFactoryBean svrFactory = new JaxWsServerFactoryBean();
                svrFactory.setServiceClass(XyzPortType.class);
                svrFactory.setAddress("/xyz");
                svrFactory.setBus(_servlet.getBus());
                svrFactory.setServiceBean(xyzServiceImpl);
                svrFactory.create();
            } catch (Throwable e) {
                e.printStackTrace();
            } finally {
            }
        }
    
    
        @Activate
        void activate(BundleContext context)
        {
        }
    
    
        @Deactivate
        void deactivate(BundleContext context)
        {
            _httpService.unregister(Alias);
        }
    

    欢迎提出将此代码移至 Bundle Activator 类的建议,但请注意,有必要确保在调用 Bundle Activator 时 HTTPService 可用。

    【讨论】:

      【解决方案2】:

      您可以实现一个捆绑激活器,在捆绑启动/停止时注册/取消注册 CXF 总线。

      要创建总线,您可以使用 BusFactory 类。创建的总线必须注册为服务。注册的服务保存在一个列表中,以便能够在捆绑停止时取消注册。

      以下(也许不是太漂亮)的例子应该会给你一个想法:

      import org.apache.cxf.Bus;
      import org.apache.cxf.BusFactory;
      import org.osgi.framework.BundleActivator;
      import org.osgi.framework.BundleContext;
      import org.osgi.framework.ServiceRegistration;
      ...
      
      
      public class MyBundleActivator implements BundleActivator {
      
         private final List<ServiceRegistration> serviceReferences = new ArrayList<>();
      
         private Bus cxfBus;
         private BundleContext bundleContext;
      
         @Override
         public void start(BundleContext bundleContext) throws Exception {
            this.bundleContext = bundleContext;
            createAndRegisterCxfBus();
         }
      
         private void createAndRegisterCxfBus() {
            cxfBus = BusFactory.newInstance().createBus();
            cxfBus.setExtension(MyBundleActivator.class.getClassLoader(), ClassLoader.class);
            registerService(Bus.class.getName(), cxfBus);
         }
      
         private void registerService(String serviceTypeName, Object service) {
            Dictionary properties = new Properties();
            ServiceRegistration serviceReference = bundleContext.registerService(serviceTypeName, service, properties);
            serviceReferences.add(serviceReference);
         }
      
         @Override
         public void stop(BundleContext bundleContext) throws Exception {
            unregisterServices();
         }
      
         private void unregisterServices() {
            for (ServiceRegistration serviceReference : serviceReferences) {
               serviceReference.unregister();
            }
         }
      } 
      

      对于 JAX-RS 服务,您现在可以这样继续:

        JAXRSServerFactoryBean serviceFactory = new JAXRSServerFactoryBean();
        serviceFactory.setBus(cxfBus);
      
        ... configure with providers etc using factory API ....
      
        Server server = serviceFactory.create();
      

      更多信息请参见http://cxf.apache.org/docs/jaxrs-services-configuration.html

      【讨论】:

      • 我实际上尝试过这样的事情,但没有成功。似乎在激活 HTTPService 和/或 CXF 包之前调用 BusFactory.newInstance().createBus() 会导致新总线自动与“/cxf”别名关联。当稍后加载 CXF 包时,该代码还会创建一个新包并将其与“/cxf”别名相关联。这会导致冲突。我想出了一种避免这种重复别名异常的方法,并将在此线程上记录该解决方案。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-06-10
      • 1970-01-01
      • 2014-06-27
      • 1970-01-01
      • 1970-01-01
      • 2020-06-01
      相关资源
      最近更新 更多