【问题标题】:Build a reflection based service for OSGi with maven使用 maven 为 OSGi 构建基于反射的服务
【发布时间】:2016-03-11 10:35:21
【问题描述】:

我正在考虑修改我现有的 java 框架以使用 OSGi。我有几个组件依赖于反射并与任何类型的类一起工作(如 bean 和持久性服务)。 我对 OSGi 还不是很有经验,但据我所知,OSGi 包只能看到它显式导入的包中的类。如果我使用 maven-bundle-plugin 构建一个包并指定一个通配符作为导入包,它会解析代码在构建时引用的包。我需要代码来处理构建时未知的包中的类。

我想要实现的是,bundle-A 可以使用 bundle-B 中的持久性框架来持久化属于 bundle-C 的类。虽然 bundle-B 在构建时不知道 bundle-C。

我需要哪些清单条目以及如何使用 maven-bundle-plugin 设置它们?

另外,由于同一类可以有多个版本被不同的包使用,这在 OSGi 环境中是否有意义?如果我理解正确,Bundle-A 和 Bundle-B 可能会看到 Bundle-C 的不同版本。如果 Bundle-A 现在将位于 Bundle-C 中的类的对象传递给 Bundle-B,然后在该类上使用反射,则 Bundle-B 将看到在 Bundle-C 中定义的类或在 Bundle-C 中定义的类Bundle-A 的 Bundle-C。 例如,如果我在 Bundle-C 中有以下类:

class Y {
   [...]
}

class X {
   Y y;
   [...]
}

Bundle-C 对于 Bundle-A 和 B 是不同的。B 将 X 类的对象传递给 A。如果 B 现在发现字段 y 并解析它的类,它将解析 Y,因为它在它的 Bundle-C 版本中还是 A 知道的版本?

简而言之,即使我有一个可以从所有包中导入所有类的包,这对于例如创建一个将对象持久保存到数据库中的服务是否有用?

【问题讨论】:

    标签: java maven osgi


    【解决方案1】:

    类加载的整个问题仅在您加载类时才相关。反射在 OSGi 中的工作方式与在 OSGi 外部相同。

    因此,如果您在 bundle b 中有一个将 Object 作为参数的方法。然后,您可以从 bundle A 中调用此方法,并使用 bundle c 中定义的 Class 的实例。即使 bundle b 没有对象包的导入,它仍然可以使用反射来处理对象。

    如果您想在不导入包的包中按名称加载类,安全的方法是为其提供包含类的包的类加载器。

    例如,您可以在 bundle b 中使用此方法:

    public Object loadTest(ClassLoader loader, String name) {
        return loader.loadClass(name);
    }
    

    现在的问题当然是如何在 bundle a 中获取 bundle b 的类加载器。最简单的方法是使用 MyClass myObject = new MyClass() 从 b 创建一个类。 Bundle a 可以在导入包时执行此操作。然后你可以使用myObject.getClass().getClassLoader() 来获取bundle b的类加载器。

    在 OSGi 中,每个对象的类加载器都是定义它的包的类加载器(如果你不做任何奇怪的事情的话)。

    如果这不可能,你可以通过使用来获取包的类加载器

    ClassLoader loader = bundle.adapt(BundleWiring.class).getClassLoader();
    

    【讨论】:

    • 谢谢。因此,如果类由类加载器加载,则其字段的类也由相同的类加载器填充。我认为当调用 getFields 时线程的类加载器可能会延迟加载它们,它会看到不同版本的字段类。我猜这意味着调用 newInstance 将使用构造类的类加载器,而不是调用者的类加载器。如果您不介意一个额外的问题,我可以依赖具有不同哈希码的相同类的不同版本还是依赖于 JVM?我需要为每个类缓存一个 DAO(-version)
    • OSGi 类加载不使用线程上下文类加载器。字段通常由它们所在类的捆绑类加载器加载。但是如果字段类位于捆绑包之外,则此类加载器引用另一个捆绑包类加载器。所以字段类可能有不同的类加载器。我认为哈希码应该不同,但从未尝试过。
    • 类的标识来自于完全限定的类名,以及定义它的类加载器。 hashCode 不会帮助您区分类别。
    • 感谢您花时间回答我的问题。我想将一个大项目转换为 OSGi 是一项比我想象的更大的任务。虽然 OSGi 是一个很棒的概念,但它似乎真的假设它存在于真空中。与使用 java serviceloader 或类似机制的遗留组件交互似乎相当棘手。最重要的是,我发现类加载的工作方式非常令人困惑。不幸的是,我发现的大多数文档都没有真正处理这些主题,并假设整个应用程序及其所有依赖项都是为 OSGi 编写的。
    【解决方案2】:

    您在一篇文章中有多个问题:)

    要在 OSGi 环境中设置 JPA,您可以check my blog

    OSGi 环境中的 JPA 实现以另一种方式工作。它挂钩到一个包监听器,如果一个包以持久(@Entity)类启动,它将加载它们。

    关于班级版本:

    通常 - 如果您希望某个服务包识别您的类,您可以使用包片段“注入”它。在你的情况下 - 你有一个直接的依赖关系(X 依赖于 Y),因此任何加载类 X 的包都将加载类 Y(具有特定版本)。

    在 OSGi 环境中,您可以使用不同的类版本,但不能混合使用它们。实际上,捆绑包取决于特定的类版本(已声明或首次找到)。事实上——每个类都由它的名字和类加载器标识来标识。因此,强制捆绑使用来自不同类加载器(版本)的相同类将导致“类加载器中毒”和许多难以跟踪的异常。

    玩得开心

    【讨论】:

    • 感谢您提供更多信息。我应该提到我使用自己的不是 JPA 的持久性框架。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-05-09
    • 2013-03-21
    • 1970-01-01
    • 1970-01-01
    • 2017-07-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多