【问题标题】:how useful is to create an osgi utility bundle创建 osgi 实用程序包有多大用处
【发布时间】:2017-01-22 11:44:41
【问题描述】:

我正在尝试使用 OSGi 框架开发一个简单的应用程序。我的问题涉及框架中可用的“实用程序包”:让我用一个非常冗长的例子来解释。目前我正在尝试构建一个我的捆绑包将发送的事件。

据我了解,我需要做以下事情(event admin felix):

public void reportGenerated(Report report, BundleContext context)
    {
        ServiceReference ref = context.getServiceReference(EventAdmin.class.getName());
        if (ref != null)
        {
            EventAdmin eventAdmin = (EventAdmin) context.getService(ref);

            Dictionary properties = new Hashtable();
            properties.put("title", report.getTitle());
            properties.put("path" , report.getAbsolutePath());
            properties.put("time", System.currentTimeMillis());

            Event reportGeneratedEvent = new Event("com/acme/reportgenerator/GENERATED", properties);

            eventAdmin.sendEvent(reportGeneratedEvent);
        }
    }

现在,由于一个 OSGi 应用程序可能有很多包,我想为每个包创建一个 Event 的子类(例如,我有一个名为“BundleExample”的包?在它的导出类中会有一个“BundleExampleEvent”) .我知道这不会添加任何信息,因为您可以通过查看“主题”来知道您收到了哪个事件,但请暂时耐心等待。

现在,Event 构造函数需要一个主题和一个Map<String, Object>。但是,为了“简化”事件构造函数,我只想将主题和参数列表放入地图中。例如这里可能是一个 BundleExampleEvent 类:

public class BundleExampleEvent extends Event{

    private int importantVariable;

    public BundleExampleEvent(String topic, int importantVariable) {
        super(topic, Utils.toMap("importantVariable", importantVariable));
        //here toMap is static
    }

    public int getImportantVariable() {
        return this.importantVariable;
    }   
}

好的,请注意Utils.toMap:这是一个允许您将String, Object 序列转换为Map 的函数。好的,现在Utils 是实用程序类的一个示例(愚蠢,无用,但仍然是实用程序类)。 本着 OSGi 的精神,我也想让这个实用程序类成为一个包:我的想法是在框架启动时启动这个 Utils 包,然后每当我需要它的一个实用程序时,我想获取一个通过@Reference注解引用。

这在任何捆绑接口实现中都可以很好地工作,如下所示:

@Component
public class BundleExampleImpl implements BundleExample {
   @Reference
   private Utils utils;

   @Override
   public String sayHello() {
      return this.utils.fetchHello();
      //another useless utility function, but hopefully it conveys what i'm trying to do
   }
}

但是其他类(即在工作期间由 BundleExampleImpl 调用)呢?例如BundleExampleEvent 呢?我需要从sayHello 方法调用它,并且我想在该类中使用这个实用程序来计算地图!在前面的例子中我使用了一个静态函数,但是我想使用Utils OSGi 给我的引用。

当然,我可以在 BundleExampleEvent 的构造函数中添加一个参数以满足链接,但我宁愿不这样做,因为某些东西依赖于“实用程序类”非常愚蠢";我的问题是:

  1. 如果我想要“实用程序包”,这是唯一可用的方法吗?
  2. 或者我可以做一些奇怪的事情,比如在我的BundleExampleEvent 中添加 Utils 的引用;即这样的事情:

    public class BundleExampleEvent extends Event{
        @Reference
        private Utils utils;
        private int importantVariable;
    
        public BundleExampleEvent(String topic, int importantVariable) {
            super(topic, Utils.toMap("importantVariable", importantVariable));
            //here toMap is static
        }
    
        public int getImportantVariable() {
            return this.importantVariable;
        }   
    }
    
  3. 或者也许拥有“实用程序包”的整个想法只是纯粹的垃圾?

感谢您的回复。希望我能以最清晰的方式表达我的问题

【问题讨论】:

    标签: java osgi osgi-bundle


    【解决方案1】:

    在您的情况下,Utils utils 将是一个 OSGi 服务。然后,您想在不是 BundleExampleEvent 之类的服务的对象中使用此服务。

    您可以做的是创建一个服务,该服务创建 BundleExampleEvent 实例并为其提供 OSGi 服务。有点像工厂即服务。问题在于 OSGi 中的服务是动态的。如果 BundleExampleEvent 实例所需的服务消失,则必须丢弃该对象。所以这只适用于短命的对象。

    在 eventadmin 示例中,一个不同的解决方案是不使用特殊的事件类,而是创建一个具有发送此类事件的方法的服务。然后所有的魔法都会在这个方法中发生,结果将是一个没有进一步逻辑的事件。您还可以使用 DS 将 EventAdmin 注入该服务。 这在 OSGI 中效果很好,但具有贫血域模型 (http://www.martinfowler.com/bliki/AnemicDomainModel.html) 的缺点。

    我不确定更喜欢哪个变体。

    【讨论】:

    • 据我了解,为了避免将 Utils 的引用放在构造函数中,我需要为此唯一目的创建另一个服务。听起来很多代码几乎没有。我认为我最好的选择是在构造函数中传递 Utils 实例或放弃 Utils 包。在您看来,哪一个是对 OSGi 最友好的选项?我是 OSGi n00bie,所以我不确定最佳解决方案。谢谢!
    • 如果您的 Utils 类不需要服务或具有静态方法,那么只需像在普通 java 中一样使用它。你不需要注入它。因此,您可以在事件对象中调用此类方法,而无需任何构造函数注入。顺便提一句。我不确定是否建议使用专门的 Event 类。至少我没见过。
    • 我认为对 Event 进行专门化实际上是没有用的......你从专门化它们中得到的唯一东西就是一些 getter 和 setter。关于实用程序类...我不确定,因为如果实用程序类内部存在错误,解决它的唯一方法是手动停止框架,更新类然后重新启动它;如果它是一个 OSGi 注入包,我可以只更新包本身。我认为这里我们处于一个简单的编码 - 健壮性权衡场景。您是否已经看过实用程序类捆绑包?只是为了了解我的解决方案是否已被其他人使用!
    • 在很多情况下,类直接在 OSGi 中使用。所有简单的库都以这种方式工作。只要您的类不需要配置或其他服务,简单地用新方法实例化它或使用静态方法就没有问题。不过要注意名为 Util 的类或包。他们倾向于吸引各种方法。所以它们的内聚力很低,并且间接地耦合了不应该相关的类。关于运行时的更新。这仍然可以工作,但您必须使用这些类刷新并重新启动所有捆绑包。不过,运行时更新并不是那么重要。
    • 我认为如果您想保持应用程序的高可用性,运行时更新是必不可少的......我错了吗?在考虑 OSGi 时,我确信模块化和动态更新是框架的强项……或者我只是有一个幼稚的看法?
    【解决方案2】:

    我认为 Utils 作为服务没有任何意义。事物只有在可以想象有多种实现的情况下才应该是一种服务。在您的情况下,Util 功能的使用者只需要一个实现......实现是合同。

    我什至不认为 utils 代码应该放在一个包中。只需将其放入静态链接到需要它的包中的库即可。

    【讨论】:

    • 静态链接是一个很好的概念,但我认为它并没有被用户很好地理解。我也花了一段时间来了解如何以及在哪里使用它。如果你还没有,也许值得写一篇博文:-)
    • 这就是我所希望的 :-) 谢谢
    • 经过一番思考,我完全同意你的看法:使用捆绑包来包含实用程序是没有用的,因为实现是合同。只有一件事我不确定。使用静态链接(通过条件包),如果我需要更新实用程序类(可能是因为我添加了一个新的实用程序方法),我可以使用此类实用程序卸载每个包,物理更改实用程序 jar 并重新安装所有内容吗?我要做的是避免重新启动整个应用程序(尽管我知道如果在所有捆绑包中都使用实用程序类,则两种解决方案都是平等的)
    • 这取决于您所谈论的变化的性质。如果您添加了一项功能,则无需更新每个捆绑包,只需更新需要新功能的捆绑包。如果它是重要的错误修复或安全更新,那么是的,您需要更新使用它的每个捆绑包。不过,您不必重新启动整个应用程序 - Bundle.update() 方法可以在几毫秒内完成。
    • 我会接受您的回答,因为如果其他人看到这个问题,您的回答正是包含为什么创建实用程序包是无用的(引用您“实施就是合同”)。添加静态链接对于像我这样的未来新手开发者来说也是一个很好的参考
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-06
    • 2011-11-08
    • 1970-01-01
    • 2015-01-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多