JDBC/OSGi 以及如何动态加载驱动程序而无需在捆绑包中显式声明依赖项?

发布于 2024-08-30 08:05:54 字数 893 浏览 3 评论 0原文

这是一件大事。

我有一个结构良好但整体的代码库,它具有原始的模块化架构(所有模块都实现接口但共享相同的类路径)。当我在可能具有不同冲突版本的库的应用程序服务器上进行部署时,我意识到这种方法的愚蠢之处以及它所代表的问题。

我现在依赖大约 30 个罐子,并且正在将它们捆绑起来。现在我的一些模块很容易声明其版本依赖项,例如我的网络组件。它们静态引用 JRE 和其他 BNDded 库中的类,但我的 JDBC 相关组件通过 Class.forName(...) 实例化,并且可以使用任意数量的驱动程序之一。

我将按服务区域将所有内容分解为 OSGi 包。

  • 我的核心类/接口。
  • 报告相关组件。
  • 数据库访问相关组件(通过 JDBC)。
  • 等等......

我希望我的代码仍然能够在没有 OSGi 的情况下通过具有所有依赖项的单个 jar 文件使用,并且根本不需要 OSGi(通过 JARJAR),并且还可以通过 OSGi 元数据和粒度包进行模块化带有依赖信息。

  • 如何配置我的捆绑包以及 我的代码,这样它就可以 动态利用任何驱动程序 类路径和/或 OSGi 内 容器环境 (Felix/Equinox/等)?

  • 是否有一个运行时方法来检测我是否在跨容器(Felix/Equinox/等)兼容的 OSGi 容器中运行?

  • 如果我在 OSGi 容器中,我是否需要使用不同的类加载机制?

  • 我是否需要将 OSGi 类导入到我的项目中才能通过我的数据库模块加载捆绑时未知的 JDBC 驱动程序?

  • 我还有第二种获取驱动程序的方法(通过 JNDI,这仅在应用服务器中运行时才真正适用),我是否需要更改 OSGi 感知应用服务器的 JNDI 访问代码?

This is a biggie.

I have a well-structured yet monolithic code base that has a primitive modular architecture (all modules implement interfaces yet share the same classpath). I realize the folly of this approach and the problems it represents when I go to deploy on application servers that may have different conflicting versions of my library.

I'm dependent on around 30 jars right now and am mid-way though bnding them up. Now some of my modules are easy to declare the versioned dependencies of, such as my networking components. They statically reference classes within the JRE and other BNDded libraries but my JDBC related components instantiate via Class.forName(...) and can use one of any number of drivers.

I am breaking everything up into OSGi bundles by service area.

  • My core classes/interfaces.
  • Reporting related components.
  • Database access related components (via JDBC).
  • etc....

I wish for my code to be able to still be used without OSGi via single jar file with all my dependencies and without OSGi at all (via JARJAR) and also to be modular via the OSGi meta-data and granular bundles with dependency information.

  • How do I configure my bundle and
    my code so that it can
    dynamically utilize any driver on the
    classpath and/or within the OSGi
    container environment
    (Felix/Equinox/etc.)?

  • Is there a run-time method to detect if I am running in an OSGi container that is compatible across containers (Felix/Equinox/etc.) ?

  • Do I need to use a different class loading mechanism if I am in a OSGi container?

  • Am I required to import OSGi classes into my project to be able to load an at-bundle-time-unknown JDBC driver via my database module?

  • I also have a second method of obtaining a driver (via JNDI, which is only really applicable when running in an app server), do I need to change my JNDI access code for OSGi-aware app servers?

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

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

发布评论

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

评论(3

不乱于心 2024-09-06 08:05:54
  • 在 OSGi 环境中使用任何驱动程序都需要您使用 DynamicImport-Package: * 语句,以便您的捆绑包可以在您使用 Class.forName(..) 加载驱动程序时解析这些包。
  • 也许最简单的方法是尝试访问 org.osgi.framework 包中的类。这些至少应该始终存在于 OSGi 环境中(参见下面的代码片段)。还有更复杂的机制,所以如果您需要更高级的东西,请告诉我。另外,请查看 OSGi R4.2 核心规范,第 3.8.9 段,其中显示了查找类的 Bundle 和 BundleContext 的一些方法,因此间接有助于确定您是否在框架中。
  • 这取决于你在做什么,这里没有通用的“是”或“否”答案。 OSGi 使用类加载器,其执行方式对于标准 Java 应用程序而言并不“典型”,但根据您正在执行的操作,您可能不会注意到。
  • 不。
  • 看看最近发布的 OSGi 企业规范。他们有一章介绍 OSGi 中的 JNDI 集成,这可能允许您(大部分)不修改代码。

一个简单的示例片段:

 public static boolean inOSGi() {
  try {
   Class.forName("org.osgi.framework.FrameworkUtil");
   return true;
  }
  catch (ClassNotFoundException e) {
   return false;
  }
 }

只要确保如果将此代码放入包中,该包应该导入 org.osgi.framework (否则它将永远找不到该类)。

  • Utilizing any driver within the OSGi environment requires you using a DynamicImport-Package: * statement so your bundle can resolve these packages when you load a driver with Class.forName(..).
  • Probably the easiest way is to try to access a class that is in the org.osgi.framework package. Those should at least be always around in an OSGi environment (see snippet below). There are more sophisticated mechanisms, so let me know if you need something more advanced. Also, take a look at the OSGi R4.2 core spec, paragraph 3.8.9 which shows some methods of finding the Bundle and BundleContext of a class and therefore indirect helps in determining if you're in a framework or not.
  • That depends on what you're doing, no generic "yes" or "no" answer here. OSGi uses classloaders and does so in a way that is not "typical" for a standard Java application, but depending on what you're doing, you might not notice.
  • No.
  • Take a look at the recently released OSGi enterprise specs. They have a chapter on JNDI integration in OSGi which probably allows you to leave your code (largely) unmodified.

A simple example snippet:

 public static boolean inOSGi() {
  try {
   Class.forName("org.osgi.framework.FrameworkUtil");
   return true;
  }
  catch (ClassNotFoundException e) {
   return false;
  }
 }

Just make sure that you if you put this code in a bundle, the bundle should import org.osgi.framework (otherwise it will never find that class).

沒落の蓅哖 2024-09-06 08:05:54

我在 Eclipse RCP 中为 OSGI 制作了一个 JDBC 驱动程序管理器,我将带您了解如何很好地使用 OSGI。首先,忘记 DynamicImport-Package,使用 OSGI 的唯一好方法是安装/启动/停止捆绑包并按照设计方式使用 OSGI 机制。

  1. 您拥有 JDBC 捆绑包,并创建另一个“驱动程序捆绑包”,其中包含 DriverClass 的初始化、连接逻辑并添加必要的公共库,例如 dbcp2 和 pool2。

  2. 将驱动程序包导出为 JAR/ZIP 并将其作为资源包含在您的 JDBC 包中。

  3. 让您的 JDBC 包将驱动程序包解压缩到其工作区域中。

    String workdir= Platform.getStateLocation(jdbc_bundle).toPortableString();
    
  4. 以编程方式添加驱动程序 jar 并相应地修改驱动程序包的 MANIFEST.MF 文件。

    以编程

  5. 从工作区以编程方式加载驱动程序包

    getBundleContext().installBundle("文件:/"+workdir);
    
  6. 以编程方式修改驱动程序列表时,根据需要使用bundle.start()、stop()、uninstall()。

I made a JDBC driver manager for OSGI in an Eclipse RCP and I will take you through how to play nice with OSGI. First, forget about DynamicImport-Package, the only good way to use OSGI is to install/start/stop bundles and use the OSGI mechanism the way it was designed.

  1. You have your JDBC bundle, and create another "Driver bundle" which has the initialization of the DriverClass, the Connection logic and add the necessary commons libraries such as dbcp2 and pool2.

  2. Export the Driver bundle as a JAR/ZIP and include it in your JDBC bundle as a resource.

  3. Let your JDBC bundle unzip the Driver bundle in its work area.

    String workdir= Platform.getStateLocation(jdbc_bundle).toPortableString();
    
  4. Programmatically add driver jars and modify the Driver bundle's MANIFEST.MF file accordingly.

  5. Load the Driver bundle programmatically from the work area

    getBundleContext().installBundle("file:/"+workdir);
    
  6. Use bundle.start(), stop(), uninstall() as necessary when programmatically modifying the list of drivers.

素食主义者 2024-09-06 08:05:54

pax-jdbc 可用于通过声明方式委托数据源,这意味着您可以在 ConfigAdmin 服务中创建配置条目,并且可以通过 JNDI 访问数据源。 JDBC 驱动程序作为捆绑包进行部署。 (大多数都有 OSGi 版本)

例如:

配置条目 PID 是 org.ops4j.datasource-test

属性:

osgi.jdbc.driver.name=H2
databaseName=test
user=sa
password=
dataSourceName=testds-h2

服务由给定的 dataSourceName 标识。因此,您可以使用 (&(objectClass=javax.sql.DataSource)(dataSourceName=test2)) 对其进行过滤。

您可以通过 JNDI 访问数据源:

osgi:service/javax.sql.DataSource/(osgi.jndi.service.name=test2)

The pax-jdbc can be used to delegate dataSources via declarative way, means you can create a config entry in ConfigAdmin service, and the dataSource can be accessed via JNDI. The JDBC driver is deployed as bundle. (most of them have OSGi version)

For example:

The config entry PID is org.ops4j.datasource-test

Properties:

osgi.jdbc.driver.name=H2
databaseName=test
user=sa
password=
dataSourceName=testds-h2

The service is identified by the given dataSourceName. So you can filter for it with (&(objectClass=javax.sql.DataSource)(dataSourceName=test2)).

And you can access the datasource via JNDI:

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