有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

带有组件XML文件的java OSGI DeclarativeService Multiton

我需要一个给定OSGI组件的multiton实例,即一些捆绑包将获得相同的实现实例,而其他捆绑包需要另一个实例。如果可能的话,我需要使用XML文件而不是注释(如@Component)。我使用的是一个混合OSGi4.3平台,由eclipse&;费利克斯

比方说,我的服务界面如下所示:

public interface SocketService {

    // Does nothing if already listening on given port
    public void startListening(int port);

    public String getNextMessage();
}

声明性XML文件如下所示,工作正常:

<?xml version="1.0" encoding="UTF-8"?>
  <scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="SocketService">
    <implementation class="declarativemultiton.service.impl.SocketServiceImpl"/>
    <service>
      <provide interface="declarativemultiton.service.SocketService"/>
    </service>
</scr:component>

这些是具有相同语义的使用者类:

public class Consumer1 {

    public void activate() {
        System.out.println("Consumer1 activated");
    }

    public void setSocketService(SocketService service) {
        System.out.println("Consumer1 got SocketService@" + System.identityHashCode(service));
    }
}

public class Consumer2 {

    public void activate() {
        System.out.println("Consumer2 activated");
    }

    public void setSocketService(SocketService service) {
        System.out.println("Consumer2 got socketservice@" + System.identityHashCode(service));
    }
}

以及它们的组件定义XML:

<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="Consumer1" immediate="true">
   <implementation class="declarativemultiton.consumer1.Consumer1"/>
   <reference bind="setSocketService" cardinality="1..1" interface="declarativemultiton.service.SocketService" name="SocketService" policy="static"/>
</scr:component>

<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="Consumer2" immediate="true">
   <implementation class="declarativemultiton.consumer2.Consumer2"/>
   <reference bind="setSocketService" cardinality="1..1" interface="declarativemultiton.service.SocketService" name="SocketService" policy="static"/>
</scr:component>

一切正常,两个组件得到相同的实例:

Socket Service Impl activated
Consumer1 got SocketService@1769618707
Consumer1 activated
Consumer2 got socketservice@1769618707
Consumer2 activated

我需要Component1和Component2来获取不同的SocketService实例,而Component2和Component3(未显示)则具有相同的SocketService实例

如果我将配置策略更改为“需要”,则不会激活任何使用者组件:

<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" configuration-policy="require" name="SocketService">
   <implementation class="declarativemultiton.service.impl.SocketServiceImpl"/>
   <service>
      <provide interface="declarativemultiton.service.SocketService"/>
   </service>
</scr:component>    

这就是我迷路的地方,我不知道如何将配置动态地传递给SocketService。我在读有关ConfigurationAdmin、ManagedService、ManagedServiceFactory、ComponentFactory等方面的文章时,一直很紧张。我找不到一个具体、简洁的解决方案。有一些相互冲突的方法,比如这个答案https://stackoverflow.com/a/4129464/330464说不要使用ManagedService,但Karaf教程http://sully6768.blogspot.com.tr/2012/09/declarative-services-with-karaf-part-4.html说明了它的使用


共 (4) 个答案

  1. # 1 楼答案

    首先,你的问题听起来有点可疑?如果不同的接收器可以指定要侦听的不同端口,您如何共享服务?startListening方法听起来像是以前尝试共享同一个实例并在其外观后面调度到不同服务器时留下的

    我假设您希望将服务连接到不同的捆绑包。正如David所说,这最好通过配置来完成

    方法是通过工厂配置创建SocketListener服务,并使用引用的目标筛选器来获得正确的筛选器:

    @Component
    public class Consumer1 {
      @Reference( target="(group=1)")
      SocketListener listener;
    
    }
    
    @Component
    public class Consumer2 {
      @Reference( target="(group=2)")
      SocketListener listener;
    
    }
    
    @Designate( Config.class, factory=true )
    @Component
    public class SocketListenerImpl extends Thread 
      implements SocketListener {
      @interface Config {
        int port();
        String group();
      }
      private ServerSocket server;
    
      @Activate void activate(Config config ) {
        server = new ServerSocket( config.port());
        super.start();
      }
    
      public void run() { ... }
    
      @Override public String getNextMessage() { ... }
    }
    

    只需转到web控制台并在那里编辑您的配置;它将显示属性的GUI。代码中未使用group属性,但它将作为服务属性提供,以便使用者可以对其进行目标选择

    请注意,目标筛选器也可以由配置覆盖。在com.example.Consumer1PID上使用像target.listener=(group=3)这样的属性可以完成这项工作

    另外,这个示例是当前的OSGiR6,但是R4中使用的bnd注释也可以实现每个功能。三,

    第2页。正如大卫所说,看看http://enroute.osgi.org/services/org.osgi.service.coordinator.htmlhttps://github.com/osgi/osgi.enroute.examples/tree/master/osgi.enroute.examples.component.application如果你发现缺少公共关系,不要犹豫提供公共关系

  2. # 2 楼答案

    您不会说组件1、2和3所在的捆绑包。您可以使用servicefactory=true让DS为每个消费捆绑包创建一个不同的SocketService实例。在DS 1.3(在Core R6上)中,您甚至可以使用新的PrototypeServiceFactory支持为所有使用组件创建不同的实例。但是,如果您想要完全控制某些任意组件使用相同的SocketFactory实例,而其他组件使用不同的SocketFactory实例,那么您就会遇到一个使用DS很难解决的问题

  3. # 3 楼答案

    我认为使用服务属性来识别或区分使用组件上的SocketFactory实例和目标属性以确定使用哪一个是正确的方法,但我建议使用配置,而不是每个实现类使用多个组件xml。我不太清楚SocketFactory或consumer有多少实现类。为了举例说明,我将分别假设一个

    您可以通过config admin使用DS组件的配置,而不是复制组件xml并修改其中的属性。Peter Kriens对DS有很好的解释,包括此处的配置: http://enroute.osgi.org/services/org.osgi.service.component.html。以下是一些步骤,更详细地介绍了使用配置设置引用:

    1. 将配置pid添加到组件xmls。假设socketFactory为socketFactory,consumer为consumer

    2. 安装配置管理员。我认为felix和eclipse都很好用,我只使用过felix

    3. 在希望安排套接字工厂启动的捆绑包中,执行一些获取ConfigAdmin实例的代码并调用

      Configuration sfc = ca.createFactoryConfiguration("socketFactory", null);
      Hashtable<String, Object> props = new Hashtable<String, Object>();
      props.put("socketType", "MyType");
      sfc.update(props);
      

    如果此代码与SocketFactory代码在捆绑包中,则可以省略null参数。 这将导致SocketFactory组件具有socketType=MyType服务属性,类似于您对组件属性所做的操作

    1. 在要安排消费者设置的捆绑包中,使用目标过滤器执行类似操作:

      Configuration cc = ca.createFactoryConfiguration("consumer", null);
      Hashtable<String, Object> props = new Hashtable<String, Object>();
      props.put("SocketService.target", "(socketType=MyType)");
      cc.update(props);
      

    这将生成具有指定目标筛选器的使用者组件

    或者,您也可以使用felix fileinstall来从属性文件安装配置。这是一个很好的声明,但我没有任何使用它的经验,我也看到一些人在把所有的部分排列好以便工作时遇到困难。在工作中,我有幸使用一个基于xml的系统:它从元类型生成一个模式,并将xml配置文档(符合生成的模式)与元类型结合起来生成配置。它可以从嵌套的xml生成目标筛选器元素。我经常希望有一个开源版本

    顺便说一句,您可能希望重新考虑避免使用spec ds注释。它们不会在运行时使用,而是在组装包时由bnd处理。(您正在使用bnd,是吗?)。Bnd将生成组件。xml是与您的组件兼容的尽可能最低的ds版本,它将比您手动执行的验证要多得多(至少比我手动执行的验证要多)

  4. # 4 楼答案

    复制服务的XML文件解决了我的问题,但这可能不是真正的OSGI方式

    首先,我们复制服务的组件描述符,但添加一个属性以将其与其他实现区分开来:

    <?xml version="1.0" encoding="UTF-8"?>
    <scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="SocketService2">
       <implementation class="declarativemultiton.service.impl.SocketServiceImpl"/>
       <service >
          <provide interface="declarativemultiton.service.SocketService" />
       </service>
       <property name="socketType" type="String" value="server"/>
    </scr:component>
    

    然后我们向消费组件添加target属性:

    <?xml version="1.0" encoding="UTF-8"?>
    <scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="Consumer2" immediate="true">
       <implementation class="declarativemultiton.consumer2.Consumer2"/>
       <reference bind="setSocketService" cardinality="1..1" interface="declarativemultiton.service.SocketService" 
            name="SocketService2" policy="static" target="(socketType=server)"/>
    </scr:component>
    

    服务实现类使用activate方法获取映射中的给定属性:

    public class SocketServiceImpl implements SocketService {
    
        public void activate(Map<String, Object> props) {
            System.out.println("SocketServiceImpl@" + System.identityHashCode(this) + " activated with props: "
                    + Joiner.on(';').withKeyValueSeparator("=>").join(props.entrySet()));
        }
    
        @Override
        public void startListening(int port) {
            //
        }
    
        @Override
        public String getNextMessage() {
            //
            return null;
        }
    
    }
    

    只需复制XML文件,而不复制实现类,也不公开实现,我们就可以向使用者提供单独的实例:

    SocketServiceImpl@936816937 activated with props: component.name=>SocketService;component.id=>0;objectClass=>[Ljava.lang.String;@5062e9b4
    Consumer1 got SocketService@936816937
    Consumer1 activated
    SocketServiceImpl@2029093081 activated with props: objectClass=>[Ljava.lang.String;@37426497;socketType=>server;component.name=>SocketService2;component.id=>1
    Consumer2 got socketservice@2029093081
    Consumer2 activated
    Consumer3 got SocketService@2029093081
    Consumer3 activated

    如上所述,我怀疑有更好的方法来实现这一点,但我厌倦了现有的各种不同的文档