Java 带有组件XML文件的OSGI DeclarativeService Multiton
我需要一个给定OSGI组件的multiton实例,即一些捆绑包将获得相同的实现实例,而其他捆绑包需要另一个实例。如果可能的话,我需要使用XML文件而不是注释(如@Component)。我使用的是一个混合OSGi4.3平台,由eclipse和felix的捆绑包组成 比方说,我的服务界面如下所示:Java 带有组件XML文件的OSGI DeclarativeService Multiton,java,osgi,Java,Osgi,我需要一个给定OSGI组件的multiton实例,即一些捆绑包将获得相同的实现实例,而其他捆绑包需要另一个实例。如果可能的话,我需要使用XML文件而不是注释(如@Component)。我使用的是一个混合OSGi4.3平台,由eclipse和felix的捆绑包组成 比方说,我的服务界面如下所示: public interface SocketService { // Does nothing if already listening on given port public vo
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>
以及它们的组件定义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>
一切正常,两个组件得到相同的实例:
套接字服务Impl已激活消费者得到SocketService@1769618707
消费者1已激活
消费者2得到socketservice@1769618707
消费者2已激活 我需要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等方面的文章时,一直很紧张。我找不到一个具体、简洁的解决方案。有一些相互矛盾的方法,比如这个答案说不要使用ManagedService,但是Karaf教程介绍了它的使用。您没有说组件1、组件2和组件3在哪个捆绑包中。您可以使用servicefactory=true让DS为每个消费捆绑包创建一个不同的SocketService实例。在DS 1.3(在Core R6上)中,您甚至可以使用新的PrototypeServiceFactory支持为所有使用组件创建不同的实例。但是,如果您想完全控制某些任意组件使用相同的SocketFactory实例,而其他组件使用不同的SocketFactory实例,那么您就遇到了一个使用DS很难解决的问题。复制服务的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;
}
}
公共类SocketServiceImpl实现SocketService{
公共空间激活(地图道具){
System.out.println(“SocketServiceImpl@”+System.identityHashCode(this)+“使用道具激活”:
+Joiner.on(“;”).withKeyValueSeparator(=>”).join(props.entrySet());
}
@凌驾
公共监听(int端口){
//
}
@凌驾
公共字符串getNextMessage(){
//
返回null;
}
}
只需复制XML文件,而不复制实现类,也不公开实现,我们就可以向使用者提供单独的实例:
SocketServiceImpl@936816937用props激活:component.name=>SocketService;id=>0;objectClass=>[Ljava.lang.String;@5062e9b4消费者得到SocketService@936816937
消费者1已激活
SocketServiceImpl@2029093081用props激活:objectClass=>[Ljava.lang.String;@37426497;socketType=>server;component.name=>SocketService2;component.id=>1
消费者2得到socketservice@2029093081
消费者2已激活
消费者3得到SocketService@2029093081
消费者3已激活
如上所述,我怀疑有更好的方法来实现这一点,但我厌倦了现有的各种文档。我认为您使用服务属性来识别或区分SocketFactory实例和消费组件上的目标属性,以确定使用哪一种是正确的方法,但我建议使用配置,而不是每个实现类使用多个组件xml。我不太清楚SocketFactory或consumer有多少个实现类。为了说明这一点,我将假设每个实现类都有一个 您可以通过config admin使用DS组件的配置,而不是复制组件xml并修改其中的属性。Peter Kriens对DS有很好的解释,包括此处的配置: 。以下是一些步骤,更详细地介绍了使用配置设置引用:
Configuration sfc = ca.createFactoryConfiguration("socketFactory", null);
Hashtable<String, Object> props = new Hashtable<String, Object>();
props.put("socketType", "MyType");
sfc.update(props);
Configuration sfc=ca.createFactoryConfiguration(“socketFactory”,null);
Hashtable props=新的Hashtable();
道具放置(“socketType”、“MyType”);
证监会更新(道具);
Configuration cc = ca.createFactoryConfiguration("consumer", null);
Hashtable<String, Object> props = new Hashtable<String, Object>();
props.put("SocketService.target", "(socketType=MyType)");
cc.update(props);
Configuration cc=ca.createFactoryConfiguration(“消费者”,null);
Hashtable props=新的Hashtable();
props.put(“SocketService.target”,“(socketType=MyType)”;
抄送更新(道具);
Configuration cc = ca.createFactoryConfiguration("consumer", null);
Hashtable<String, Object> props = new Hashtable<String, Object>();
props.put("SocketService.target", "(socketType=MyType)");
cc.update(props);
@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() { ... }
}