OSGI 捆绑包和组件之间有什么区别?

发布于 2024-08-28 08:13:31 字数 407 浏览 5 评论 0原文

开始使用 osgi,我想知道捆绑包和组件之间的概念差异是什么。以及何时使用其中的哪一个。欢迎任何指点。

编辑:

组件和捆绑包提供不同的接口,因此它们可能不可互换

getting started with osgi, i wonder what's the conceptual diffence between bundles and components. And when to use which of them. Any pointers are welcome.

EDIT:

Components and Bundles provide different interfaces and therefore they are probably not interchangeable

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

予囚 2024-09-04 08:13:31

组件是:

  • 系统中的主动参与者
  • ,了解并适应它的环境
    • 环境=其他组件提供的服务
    • 环境 = 资源、设备……
  • 可以向其他组件提供服务并使用其他组件的服务
  • 有生命周期

简而言之:

  • 组件提供服务
  • Bundle 管理生命周期

一个 Bundle 只能拥有一个激活器(需要一个 BundleContext),并且可以拥有任意数量的活动组件。
这意味着您最终可能会尝试将一个激活器中几个松散相关的关注点放入一个类中。
这就是为什么管理 声明式服务的那些组件,通过 SCR (“服务组件运行时”是一个“扩展包”,实现新的和改进的 OSGi R4.2 DS - 声明式服务 - 规范)。
自 OSGi 4.2 以来尤其如此,因为现在将 DS 组件编写为 POJO 变得更加容易:activatedeactivate 方法不再需要采用 ComponentContext 参数。另请参阅惰性声明式服务


注意:

它可以帮助在 OSGi 上下文中替换这些术语并查看“我们如何到达那里”(Neil Bartlett 的优秀博客文章

以下是​​一些相关摘录,其中“模块”最终是 OSGi 捆绑包(管理声明服务的组件) ):

模块分离

我们的第一个要求是干净地分离模块,以便一个模块中的类不会不受控制地查看和隐藏其他模块中的类
在传统的 Java 中,所谓的“类路径”是一个巨大的类列表,如果多个类碰巧具有相同的完全限定名称,那么第一个类将始终被找到,而第二个类和所有其他类将被忽略。

防止类的可见性不受控制和模糊的方法是为每个模块创建一个类加载器。类加载器只能加载它直接知道的类,在我们的系统中这些类将是单个模块的内容。

模块访问级别

如果我们到此为止,那么模块将完全隔离,无法相互通信。为了使系统实用,我们需要重新添加查看其他模块中的类的能力,但我们以谨慎且受约束的方式进行。
此时,我们输入另一个要求:模块希望能够隐藏一些实现细节。

我们希望有一个“模块”访问级别,但今天的问题是 javac 编译器不知道模块边界在哪里。

我们在模块系统中选择的解决方案是允许模块仅“导出”其部分内容。如果模块的某些部分未导出,则其他模块根本看不到它。

导入时,我们应该导入我们实际需要使用的东西,无论它来自哪里,并忽略所有与它一起打包的东西。

出口和进口的粒度

OSGi 选择软件包。
Java 包的内容旨在保持一定的连贯性,但将包列为导入和导出并不会太麻烦,并且将某些包放入一个模块中并将其他包放入另一个模块中也不会破坏任何内容。
应该属于我们模块内部的代码可以放置在一个或多个非导出包中。

封装接线

现在我们有了一个模块如何隔离自身然后重新连接的模型,我们可以想象构建一个框架来构造这些模块的具体运行时实例。它将负责安装模块并构建了解各自模块内容的类加载器。

然后它会查看新安装模块的导入并尝试查找匹配的导出。

这样做的一个意想不到的好处是我们可以动态安装、更新和卸载模块。安装新模块对那些已经解析的模块没有影响,尽管它可能会使一些以前无法解析的模块得到解析。当卸载或更新时,框架确切地知道哪些模块受到影响,并在必要时更改它们的状态。

版本

我们的模块系统看起来不错,但我们还无法处理模块中随着时间的推移不可避免地发生的变化。我们需要支持版本。

我们如何做到这一点?首先,导出器可以简单地声明有关其导出的包的一些有用信息:“这是 API 的 1.0.0 版本”。导入器现在只能导入与其期望兼容且已编译/测试过的版本,并拒绝接受

打包模块和元数据

我们的模块系统需要一种方法来将模块的内容以及描述导入和导出的元数据打包到可部署单元中。

所以唯一的问题是,我们应该把元数据放在哪里,即导入和导出列表、版本等?

碰巧 OSGi 是在 2000 年之前设计的,因此它确实选择了其中一个解决方案。相反,它回顾了 JAR 文件规范,其中阐明了答案:
META-INF/MANIFEST.MF 是任意特定于应用程序的元数据的标准位置。

后期绑定

模块化难题的最后一块是实现与接口的后期绑定。我认为这是模块化的一个重要特征,尽管一些模块系统完全忽略它,或者至少认为它超出了范围。

我们应该寻找一种去中心化的方法
让我们假设每个模块可以简单地创建对象并将它们发布到其他模块可以找到它们的地方,而不是由 God Class 告诉我们要做什么。我们将这些发布的对象称为“服务”,并将它们发布的地方称为“服务注册表”。
关于服务最重要的信息是它实现的接口(或多个接口),因此我们可以将其用作主要注册密钥。
现在,需要查找特定接口实例的模块可以简单地查询注册表并找出当时可用的服务。注册表本身仍然是存在于任何模块之外的中心组件,但它不是“上帝”……相反,它就像一个共享的白板。

A component is:

  • an active participant in the system
  • aware of and adapt to its environment
    • environment = services provided by other components
    • environment = resources, devices, ...
  • may provide services to other components and use services from other components
  • have a lifecycle

In short:

  • Component provide services
  • Bundle manage the lifecycle

A bundle can have only one activator (needing a BundleContext), and can have as many active components as you want.
That means you may end up trying to fit in one activator several loosely-related concerns into a single class.
That is why it may be easier to manage those components by Declarative Services, through the SCR (the "Service Component Runtime" which is an "extender bundle" implementing the new and improved OSGi R4.2 DS - Declarative Service - specification).
This is especially true since OSGi 4.2 because it is now much easier to write DS components as POJOs: the activate and deactivate methods are no longer required to take a ComponentContext parameter. See also Lazy Declarative Service.


Note:

It can help to replace those terms in the context of OSGi and look at "how we got there" (excellent blog post by Neil Bartlett)

Here are some relevant extracts, where the "modules" end up being the OSGi Bundles (managing Components which declare Services):

Module Separation

Our first requirement is to cleanly separate modules so that classes from one module do not have the uncontrolled ability to see and obscure classes from other modules.
In traditional Java the so-called “classpath” is an enormous list of classes, and if multiple classes happen to have the same fully-qualified name then the first will always be found and the second and all others will be ignored.

The way to prevent uncontrolled visibility and obscuring of classes is to create a class loader for each module. A class loader is able to load only the classes it knows about directly, which in our system would be the contents of a single module.

Module Access level

If we stop here then modules will be completely isolated and unable to communicate with each other. To make the system practical we need to add back in the ability to see classes in other modules, but we do it in a careful and constrained way.
At this point we input another requirement: modules would like the ability to hide some of their implementation details.

We would like to have a “module” access level, but the problem today is that the javac compiler has no idea where the module boundaries lie.

The solution we choose in our module system is to allow modules to “export” only portions of their contents. If some part of a module is non-exported then it simply cannot be seen by other modules.

When importing, we should import what we actually need to use, irrespective of where it comes from and ignoring all the things that happen to be packaged alongside it.

Granularity of Exports and Imports

OSGi chooses packages.
The contents of a Java package are intended to be somewhat coherent, but it is not too onerous to list packages as imports and exports, and it doesn’t break anything to put some packages in one module and other packages in another module.
Code that is supposed to be internal to our module can be placed in one or more non-exported packages.

Package Wiring

Now that we have a model for how modules isolate themselves and then reconnect, we can imagine building a framework that constructs concrete runtime instances of these modules. It would be responsible for installing modules and constructing class loaders that know about the contents of their respective modules.

Then it would look at the imports of newly installed modules and trying to find matching exports.

An unexpected benefit from this is we can dynamically install, update and uninstall modules. Installing a new module has no effect on those modules that are already resolved, though it may enable some previously unresolvable modules to be resolved. When uninstalling or updating, the framework knows exactly which modules are affected and it will change their state if necessary.

Versions

Our module system is looking good, but we cannot yet handle the changes that inevitably occur in modules over time. We need to support versions.

How do we do this? First, an exporter can simply state some useful information about the packages it is exporting: “this is version 1.0.0 of the API”. An importer can now import only the version that is compatible with what it expects and has been compiled/tested against, and refuse to accept

Packaging Modules and Metadata

Our module system will need a way to package the contents of a module along with metadata describing the imports and exports into a deployable unit.

So the only question is, where should we put the metadata, i.e. the lists of imports and exports, versions and so on?

As it happens OSGi was designed before 2000, so it did choose either of these solutions. Instead it looked back at the JAR File Specification, where the answer is spelled out:
META-INF/MANIFEST.MF is the standard location for arbitrary application-specific metadata.

Late Binding

The final piece of modularity puzzle is late binding of implementations to interfaces. I would argue that it is a crucial feature of modularity, even though some module systems ignore it entirely, or at least consider it out of scope.

We should look for a decentralised approach.
Rather than being told what to do by the God Class, let us suppose that each module can simply create objects and publish them somewhere that the other modules can find them. We call these published objects “services”, and the place where they are published the “service registry”.
The most important information about a service is the interface (or interfaces) that it implements, so we can use that as the primary registration key.
Now a module needing to find instances of a particular interface can simply query the registry and find out what services are available at that time. The registry itself is still a central component existing outside of any module, but it is not “God”… rather, it is like a shared whiteboard.

青萝楚歌 2024-09-04 08:13:31

在 OSGi 术语中,“组件”就像一个运行时服务。每个组件都有一个实现类,并且可以选择实现一个公共接口,有效地提供这种“服务”。 OSGi 的这个方面有时被比作服务注册表模式。

根据定义,OSGi 中的组件是由捆绑包提供的。捆绑包可以包含/提供多个组件。虽然捆绑包本身可能不提供服务,但组件/声明性服务可用于使 OSGi 更加面向服务。您没有义务使用组件/服务。

In OSGi terminology a "component" is like a run-time service. Each component has an implementation class, and can optionally implement a public interface, effectively providing this "service". This aspect of OSGi is sometimes likened to a service registry pattern.

Components in OSGi are, by definition, provided by a bundle. A bundle may contain/provide multiple components. While by itself a bundle may not provide a service, components/declarative services are used to make OSGi more service oriented. You are under no obligation to use components/services.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文