【问题标题】:Dynamically setting target property in OSGi Reference annotatation在 OSGi 参考注释中动态设置目标属性
【发布时间】:2018-05-03 18:46:15
【问题描述】:

在阅读Reference target 上的article(和相应的属性)后,当target 设置为在运行时(通常针对和属性在编译时设置并由 SCR 在运行时评估)。

假设有三个服务实现分别定义@Property(name="type", value="csv")@Property(name="type", value="xls")@Property(name="type", value="pdf")

还有一位消费者:

//@Reference(target="(type=%runtime_variable%)")
Service service;

注意 %runtime_variable% 在运行时自动评估(从设置文件中读取)。


我是否应该在 @Activate/@Modified 注释方法中调用 getServiceReferences(Class<S> clazz, String filter) 以便在运行时获得正确的服务?

如果我没有显式使用@Reference并在@Activate/@Modified注解方法中动态设置目标,component.xml是如何创建的?

我可以在这里使用@Designate 元类型注释让我的生活更简单吗?

【问题讨论】:

    标签: java osgi apache-felix declarative-services


    【解决方案1】:

    article,你已经读过,已经 7 岁了,我不清楚它使用了哪些注释(是的,有几个)。我建议忽略它。今天你最好使用Declarative Services (DS) 和标准的OSGi 注释。

    简而言之,有两个重要部分:

    • 提供/消费服务的捆绑包内/OSGI-INF 文件夹中的 XML 文件
    • 服务组件运行时 (SCR) - 一个在运行时检查其他包的包,如果找到上述 XML 文件,则负责注册和连接服务。

    虽然您可以手动编写 XML 文件,但它们通常由 Bnd 或其他使用 Bnd 的构建工具(例如我们的 bnd-maven-plugin)生成。这是在构建时完成的,当时 Bnd 检查您的类的注释并使用提供的信息生成 XML 文件。因此在运行时根本不使用注解。

    至于接线,当你有

       @Reference(target="(type=pdf)")
       Service service;
    

    service 字段将自动连接到在 OSGi 的服务注册表中注册的与目标过滤器匹配的Service 服务实例之一(是的,可以有多个)。这是由 SCR 在运行时完成的。您可以通过使用其 PID 重新配置组件来在运行时更改目标。您可以使用Configuration Admin 以编程方式或通过属性文件执行此操作。

    您提到的@Designate 注释与另一个称为Metatype 的OSGi 规范有关。它允许您更好地定义配置字段的类型。 Here 您可以阅读更多关于如何将 Metatype 与声明式服务 1.3 一起使用的信息。

    关于 OSGi 注释的另一个很好的信息来源是 here(忽略 Liferay 特定的)


    为了反映您编辑的问题,您有一些选择。一种是获取所有实例:

    @Reference(
     cardinality = ReferenceCardinality.MULTIPLE,
     policy = ReferencePolicy.DYNAMIC,
     policyOption = ReferencePolicyOption.GREEDY
     )
    protected void setService(Service service, Map<String, Object> properties) {
       String type = MapUtil.getString(properties, "type");
       _services.put(type, service);
    }
    

    然后您可以从_services map 按类型获取您的服务。另一个是重新配置您的组件。例如,如果你这样定义它

    @Component(
     configurationPid = "my.component"
    )
    public class MyComponent implements ... {
       @Reference(target="(type=pdf)")
       Service myService;
    }    
    

    您可以通过您指定的my.component.cfg 对其进行配置

    myService.target=(type=somethingElse)
    

    您可以使用 Configuration Admin API 以编程方式执行相同操作。

    【讨论】:

    • 我澄清了这个问题,以便更准确地反映我的问题。我知道如何使用 SCR + 注释 + maven。我想在运行时设置reference.target或某事。这在逻辑上是等效的(为了通过配置reference.target 而不重新编译来满足特定的客户需求)。
    • 仍然,感谢您的回答和您提供的有趣资源。我会通读链接!
    • 正如我之前提到的,注释是在构建时处理的。因此@Reference(target="(type=%runtime_variable%)") 永远不会起作用。您可以使用的是获取所有已注册服务及其元数据的列表,将它们保存在本地的某种地图中,并根据运行时参数使用您需要的地图。
    • 我需要什么? @Reference 以便 bnd 创建 component.xml 和自定义 @Activate 评估服务的方法?
    • 我更新了我的答案以反映您更新的问题
    【解决方案2】:

    你可以这样做:

    @Property(name = "myService.target", label = "My Service", description = "The target reference for the MyService, e.g. use target=(type=html) to bind to services by type.")
    @Reference(name = "myService")
    private Service myService;
    

    然后你可以为你的组件com.example.impl.MyComponent.config创建配置文件:

    myService.target="(type\=pdf)"
    

    您还可以在运行时使用 Apache Felix Web 控制台 (http://localhost:8888/system/console/configMgr) 更改此值。

    【讨论】:

      【解决方案3】:

      简单地使用

      @Reference
      Service myService;
      

      然后在运行时为组件创建配置并设置过滤器,如下所示:

      myService.target=(mykey=1)
      

      【讨论】:

      • 但是在运行时如何以及在哪里创建配置?在@Activate方法中?
      • 组件不会自行配置。通常,部署者将通过配置管理员配置系统。因此,您需要确保组件的 PID 下的配置包含所需的目标属性和值。
      • 开发的产品是客户端软件。每天(重新)启动多次。这种配置是不可行的。是否可以编写一个立即启动并执行配置的组件?
      • 有几种方法可以配置配置管理员。使用 felix fileinstall,您可以从文件中加载配置。还有新的 felix 配置器。它可以在启动时从 json 加载配置。所以你可以确保配置存在。
      • 配置是持久化的,因此如果客户端重新启动,它们将自动注入与之前相同的配置。有一个组件将其他组件的配置放入配置管理中是不寻常的。通常使用配置管理代理管理配置,该代理可能使用平面文件(例如文件安装)或更复杂的机制(例如从 UI 或数据库推送数据)。
      猜你喜欢
      • 1970-01-01
      • 2017-01-15
      • 2018-08-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-05-23
      相关资源
      最近更新 更多