osgi java_使普通的旧Java OSGi兼容

osgi java

尽管OSGi在Java世界中越来越流行,但仍有许多Java应用程序和库尚未设计成可在OSGi中使用。 有时您可能需要在OSGi环境中运行这样的代码,或者是因为您想利用OSGi本身提供的好处,或者因为您只需要此特定环境提供的某些功能。 通常,您负担不起完全迁移到OSGi的负担,或者至少需要一个过渡期,在此期间,您的代码在OSGi内外均可以正常工作。 当然,您想以最小的努力做到这一点,而又不会增加软件的复杂性。

最近,我们在SAP的团队面临着类似的挑战。 我们有一个相当大的遗留纯Java应用程序,多年来,它已发展为包括许多本地框架和自定义解决方案。 我们需要为此应用程序提供基于REST的接口,因此我们要么必须包含Web服务器,要么必须在具有该Web服务器的环境中运行。 我们选择使用SAP Lean Java Server(LJS) ,后者是SAP NetWeaver Cloud背后的引擎,其中包括Tomcat和其他有用的服务。 但是,LJS基于Eclipse的OSGi实现Equinox ,因此我们需要确保我们的代码与OSGi兼容,以确保流畅的互操作性。 在此过程中,我们学到了很多有关该主题的知识,因此我想在本文中与您分享我们最有趣的发现。

为了使纯Java代码在OSGi环境中顺利运行,应满足以下先决条件:

  • 它打包为OSGi捆绑包 ,即具有有效OSGi清单的jar存档。
  • 它遵守OSGi对动态加载类施加的要求和限制。
  • 它的所有软件包仅由一个捆绑软件导出,即没有不同的捆绑软件导出同一软件包。

同样,在许多情况下,您可能需要为要从OSGi控制台启动的应用程序创建新的入口点。 如果使用Equinox,则应考虑为此目的创建一个Equinox应用程序。

请注意,满足以上要求并不意味着您不应该以任何方式将代码迁移到OSGi,使其仅在OSGi中运行,也不意味着您应从根本上将开发环境或过程更改为基于OSGi。 相反,我们的经验表明,通过以下列方式满足上述要求,很可能实现与OSGi的兼容性而不会失去在OSGi外部运行的能力,并且不会显着改变您的开发方法和工具:

  • 可以使用BND和其他基于它的工具自动生成所有OSGi清单。 在OSGi之外,不使用这些清单,但也不会造成伤害。
  • 基于Class.forName()动态加载类和自定义类加载可以由使用引擎盖下的本机OSGi服务的几乎相同的机制代替。 可以根据您的代码是否在OSGi中执行而在原始和OSGi机制之间动态切换,而对现有代码的更改很少。
  • 另外,您可以通过使用OSGi服务机制动态注册和发现“命名”实现来完全消除OSGi中的动态类加载。
  • 由多个捆绑软件导出的相同软件包应该简单地重命名。 显然,这也适用于OSGi。
  • 通过将所有特定于OSGi的代码放在有限数量的包中,可以最大程度地减少对OSGi的依赖性,这些包最好也不包含应在OSGi外部执行的代码。

以下各节提供有关如何实现此功能的更多详细信息。

包装为OSGi捆绑包

为了在OSGi环境中工作,所有Java代码都应打包为OSGi捆绑包。 这不仅适用于由构建生成的所有存档,还适用于作为软件的一部分提供的所有依赖项。

如果您的构建使用Maven,则应强烈考虑使用Maven Bundle插件 (内部使用BND)为该构建生成的所有档案生成有效的OSGi清单。 在大多数情况下,此插件的默认配置生成的清单将可以正常工作。 但是,在某些情况下,可能需要进行一些较小的调整和附加操作才能生成正确的清单,例如:

  • 为仅通过反射使用的类添加其他导入包,因此BND无法找到。
  • 为公开OSGi声明性服务的分发包指定服务组件XML。
  • 为依赖于自定义激活的捆绑软件指定捆绑软件激活器。

在我们的项目中,如下所述,在我们的父POM中配置了bundle插件:

<properties><classpath></classpath><import-package>*</import-package><export-package>{local-packages}</export-package><bundle-directives></bundle-directives><bundle-activator></bundle-activator><bundle-activationpolicy></bundle-activationpolicy><require-bundle></require-bundle><service-component></service-component>...
</properties>
...
<build><pluginManagement><plugins><plugin><groupId>org.apache.felix</groupId><artifactId>maven-bundle-plugin</artifactId><version>2.3.4</version><extensions>true</extensions><configuration><encoding>${project.build.sourceEncoding}</encoding><archive> <forced>true</forced> </archive><instructions><Bundle-SymbolicName>${project.artifactId}${bundle-directives}</Bundle-SymbolicName><Bundle-Name>${project.artifactId}</Bundle-Name><_nouses>true</_nouses><Class-Path>${classpath}</Class-Path><Export-Package>${export-package}</Export-Package><Import-Package>${import-package}</Import-Package><Bundle-Activator>${bundle-activator}</Bundle-Activator><Bundle-ActivationPolicy>${bundle-activationpolicy}</Bundle-ActivationPolicy><Require-Bundle>${require-bundle}</Require-Bundle><Service-Component>${service-component}</Service-Component></instructions></configuration><executions><execution><id>bundle-manifest</id><phase>process-classes</phase><goals><goal>manifest</goal></goals></execution></executions></plugin>...</plugins></pluginManagement>
</build>

在子POM中,我们指定任何需要具有与默认值不同的值的属性。 在我们的案例中,这种POM相对较少。

我们的大多数依赖项也没有OSGi清单,因此我们在构建过程中生成它们。 当前,这是通过使用BND wrap命令的Groovy脚本完成的。 对于我们的大多数依赖项,对清单使用通用模板就足够了。 当前,我们使用以下模板,该模板由脚本动态生成:

Bundle-Name: ${artifactId}
Bundle-SymbolicName: ${artifactId}
Bundle-Version: ${version}
-nouses: true
Export-Package: com.sap.*;version=${version_space},*
Import-Package: com.sap.*;version="[${version_space},${version_space}]";resolution:=optional,*;resolution:=optional

一世
仅在少数情况下,清单模板必须包含特定于混凝土罐的信息。 我们通过在SCM中提交这些模板并使用提交的版本而不是默认版本来捕获此类细节。

符合OSGi类加载

常用的类加载机制的替代方法

OSGi环境强加了自己的类加载机制,以下文章中对此进行了详细描述:

  • OSGi类加载
  • OSGi中的类加载和类型可见性

但是,一些普通的Java应用程序和库通常广泛依赖于创建自定义类加载器并通过Class.forName()ClassLoader.loadClass()加载类,以便使用反射 ,而我们的应用程序就是其中之一。 这在OSGi中是有问题的,如《 OSGi准备就绪-加载类》中更详细的描述。 本文提出的解决方案尽管有效,但不能直接应用于我们的案例,因为这将涉及大量更改旧代码,这是我们目前不希望做的事情。

我们发现,可以完全依靠本机OSGi机制以优雅的方式解决此问题,对于我们的大部分遗留代码都是透明的。 代替Class.forName() ,可以使用以下调用顺序:

  • 使用FrameworkUtil.getBundle()获取当前的Bundle及其BundleContext
  • 通过上一步中获得的捆绑包上下文从OSGi服务注册表中获取标准PackageAdmin服务
  • 使用PackageAdmin.getExportedPackage()ExportedPackage.getExportingBundle()查找ExportedPackage.getExportingBundle() Bundle包。
  • 最后,只需调用Bundle.loadClass()即可加载请求的类。

另外,尽管不可能直接使用低级捆绑软件类加载器,但捆绑软件类本身提供了诸如Bundle.loadClass()Bundle.getResource()类的类加载方法。 因此,可以创建一个自定义的类装入器,该类装入器包装一个包(或多个包)并委托给这些方法。

要使您的大部分遗留代码在OSGi中工作,而只需进行少量更改,就可以通过以下方式对其进行调整:

  • 如果代码在OSGi中执行,则代替调用Class.forName() ,而调用实现上述序列的方法。
  • 如果代码在OSGi中执行, BundleClassLoader要从多个jar文件中创建自定义类加载器,而BundleClassLoader与这些jar文件相对应的BundleClassLoader包中创建BundleClassLoader

为了使上述更改更加直接,我们在应用程序中引入了一个名为ClassHelper的新类。 它是一个单例,提供以下静态助手方法,这些方法委托给单个实例的相同非静态方法:

public static boolean isOsgi();
public static Object getBundleContext(Class&lt;?&gt; clazz);
public static Class&lt;?&gt; forName(String className, ClassLoader cl) throws ClassNotFoundException;
public static ClassLoader getBundleClassLoader(String[] bundleNames, ClassLoader cl);

这些方法的默认实现在基本ClassHelper类中实现了默认的非OSGi行为– isOsgi()返回false, getBundleContext()getBundleClassLoader()返回null, forName()只是委托给Class.forName()

OsgiClassHelper类继承自ClassHelper ,进而实现上述正确的OSGi行为。 我们将此类放在其自己的特殊捆绑包中,以确保包含ClassHelper和大量其他实用程序的捆绑包不受OSGi依赖关系的影响。 这个特殊的捆绑有一个Activator ,它取代了默认ClassHelper用一个实例OsgiClassHelper在束激活实例。 由于激活代码仅在OSGi中执行,因此可以确保在两种情况下均加载正确的实现。

在我们的其余代码中, ClassHelper.forName()替换Class.forName()调用,并使用ClassHelper.forName()创建自定义类加载器就ClassHelper.getBundleClassLoader()

使用OSGi服务

在许多普通的Java应用程序中,某些实现是基于字符串“ handle”(类名本身或其他名称)加载的。 通常将ClassLoader.loadClass()与自定义类加载结合使用,通常用于此目的。 OSGi提供了OSGi服务机制,用于注册和发现这种“命名”的实现,这将使您完全摆脱动态类加载。 该机制是OSGi固有的,它为上述自定义机制提供了一种非常优雅的替代方法。 与上一节中介绍的方法相比,此方法的缺点在于,它需要对代码进行一些更深层次的更改,尤其是如果它也应继续在OSGi之外运行的话。

您需要考虑以下方面:

  • 在OSGi服务注册表中注册您的接口和实现。
  • 在运行时在使用它们的代码中发现这些实现。

尽管您可以通过编程方式注册服务,但在大多数情况下,您还是希望使用OSGi声明式服务方法,因为它允许以纯声明性的方式将现有实现注册为OSGi服务。 关于发现,您可以直接通过BundleContext提供的功能查询服务注册表,也可以使用功能更强大的服务跟踪器机制 。
关于OSGi服务,尤其是声明式服务,有很多很棒的教程,其中包括:

  • OSGi服务– Lars Vogel的教程 。
  • OSGi入门: Neil Bartlett的声明式服务简介 。

在我们的案例中,我们不想太大地改变我们的代码库,因此我们只在少数几个我们认为积极影响可以证明投资合理的地方使用了OSGi服务。 目前,我们通过添加服务组件XML将现有的实现声明为服务 尽管这种基于XML的方法是标准且常用的方法,但我们发现它相当冗长且不便。 另一种方法是使用注释来指定组件和服务,如声明性服务Wiki页面和OSGi Release 4草案文件所述 。 BND已经支持这些注释。

其他注意事项

所有包装仅以一捆出口

从多个软件包中导出同一软件包在OSGi中效果不佳,因此必须避免。 如果您的代码中有这种情况,则应适当地重命名这些软件包。

公开OSGi入口点

最后,您可能需要提供一个新的入口点,以便从OSGi控制台启动您的应用程序。 如果使用Equinox,则一种合适的机制是创建Equinox应用程序 ,该应用程序包括实现org.eclipse.equinox.app.IApplication接口并提供一个附加的plugin.xml,如Eclipse插件入门:命令中所述。在线应用程序 。 可以使用startApp命令从Equinox OSGi控制台启动此应用程序。

结论

通过遵循本文中介绍的准则和方法,可以使普通的Java应用程序和库OSGi相对较少的工作量,并且对您现有的代码具有可管理的影响,从而使其兼容。

您在使Java代码与OSGi兼容方面有类似的经验吗? 如果是的话,我很想听听。

参考:通过我们的JCG合作伙伴 Stoyan Rachev的Stoyan Rachev的Blog博客,可以使Plain Old Java OSGi兼容 。

翻译自: https://www.javacodegeeks.com/2012/11/making-plain-old-java-osgi-compatible.html

osgi java

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/351692.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Matlab如何求离散点的导数

1.通过差分估算 已知同维度的x和y序列&#xff0c;则可使用diff(y)./diff(x)来估算。设x为n维向量&#xff0c;Dxdiff(x) 计算向量x的向前差分&#xff0c;DX(i)X(i1)-X(i)&#xff0c;0<i<n。 例一 y[7.86 7.84 7.82 7.77 7.72 7.68 7.61 7.51 7.42 7.33 7.21 7.07 6…

ERROR 6: GEOS support not enabled.

要学习GEOS库&#xff0c;肯定绕不开地理方面的东西。如果需要判断的两个多边形或几何图形&#xff0c;不是自己创建的&#xff0c;而是来自shapefile文件&#xff0c;那就得将GEOS库和GDAL/OGR库结合使用了。实际上只需要OGR就行了&#xff0c;但OGR和GDAL是放在一起的。OGR库…

java面向对象(this关键字)

一.this的作用 1.this 相当于是指向当前对象本身 2.成员变量和局部变量同名问题 class Person {private int age;private String name;// 给姓名和年龄初始化的构造方法Person(String name, int age) {// 当需要访问成员变量是&#xff0c;只需要在成员变量前面加上this.即可th…

c语言float二进制输出代码_下面C语言中这十四大谜题,不看答案你能做出来吗?...

C语言领取福利资料前往文末领取本篇文章《C语言的谜题》展示了14个C语言的迷题以及答案&#xff0c;代码应该是足够清楚的&#xff0c;而且我也相信有相当的一些例子可能是我们日常工作可能会见得到的。通过这些迷题&#xff0c;希望你能更了解C语言。如果你不看答案&#xff0…

平台策略:从Portlet到OpenSocial小工具再到渐进式Web应用程序:最新技术

介绍 由于世界仍在Java的掌控之中&#xff0c;因此我们经常定义所谓的基于组件的平台 。 我在2000年的OpenUSS&#xff08;开放大学支持系统&#xff09;方面拥有这一经验。 当时我有一个想法&#xff0c;就是开发一个可以使用组件体系结构和J2EE技术​​&#xff08; OpenUSS …

webm文件怎么在手机上正常播放以及在电脑上转换为mp4格式!

webm是一个开放、免费的媒体文件格式。WebM影片格式是以Matroska&#xff08;即MKV&#xff09;容器格式为基础开发的新容器格式&#xff0c;里面包括了VP8影片轨和Ogg Vorbis音轨&#xff1b;其中Google将其拥有的VP8视频编码技术以类似BSD授权开源&#xff0c;而Ogg Vorbis本…

WKT介绍

WKT&#xff0c;是一种文本标记语言&#xff0c;用于表示矢量几何对象、空间参照系统及空间参照系统之间的转换。它的二进制表示方式&#xff0c;亦即WKB(well-known binary)则胜于在传输和在数据库中存储相同的信息。该格式由开放地理空间联盟(OGC)制定。 目录 1概念2几何对象…

DS树+图综合练习--构建邻接表

题目描述 已知一有向图&#xff0c;构建该图对应的邻接表。邻接表包含数组和单链表两种数据结构&#xff0c;其中每个数组元素也是单链表的头结点&#xff0c;数组元素包含两个属性&#xff0c;属性一是顶点编号info&#xff0c;属性二是指针域next指向与它相连的顶点信息。单…

mysql datetime 间隔,MySQL datetime默认时间间隔

Is it possible to add to a default time with NOW(), 10 minutes?Ive tried something like that:CREATE TABLE table1 (date DATETIME NOT NULL DEFAULT DATE_ADD(NOW(), INTERVAL 10 MINUTE));However, it doesnt work.解决方案I dont think you can do this.The DEFAULT …

golang mysql 崩溃_mysql连接问题,goruntime里执行总是出错,程序一直崩溃

初学golang&#xff0c;尝试写一个程序&#xff0c;但是在mysql操作时遇到了问题~看网上文章&#xff0c;推荐mysql直接创建一个db全局变量&#xff0c;然后连接一次&#xff0c;以后使用到直接用这个db&#xff0c;我按照这样的方法&#xff0c;然后进行操作&#xff0c;可是程…

牛客网——点菜问题

题目描述 北大网络实验室经常有活动需要叫外卖&#xff0c;但是每次叫外卖的报销经费的总额最大为C元&#xff0c;有N种菜可以点&#xff0c;经过长时间的点菜&#xff0c;网络实验室对于每种菜i都有一个量化的评价分数&#xff08;表示这个菜可口程度&#xff09;&#xff0c;…

OGR示例:写shp,求面与面的交和差操作

编译命令&#xff1a;g main.cpp -lgdal 调用命令&#xff1a;./a.out 输出shp名称 操作选项 注释&#xff1a;操作选项&#xff08;1&#xff1a;多边形A - 多边形B&#xff0c;2&#xff1a;B - A&#xff0c;3&#xff1a;A和B的交集部分&#xff09; #include "ogr…

Spring Boot和Thymeleaf:重新加载模板和静态资源,而无需重新启动应用程序

Thymeleaf是围绕自然模板的概念设计的&#xff0c;该模板允许进行静态原型制作&#xff1a;模板逻辑不会影响用作原型的模板。 尽管这是一项很棒的技术&#xff0c;但您可能还希望在运行的Spring Boot应用程序中查看结果&#xff0c;而不必每次更改Thymeleaf视图时都重新启动服…

写cookies注意事项

在调试模式下是无法写到cookie的&#xff0c;因为cookie需要写到域名下&#xff0c;并且需要写的域名和运行的域名一致才能写入。同样在读取cookie时也只能读取到当前域名的cookie&#xff0c;无法读取其他域名的cookie。 比如下面用jquery表示在baidu.com的域名下写入cookie&a…

mysql记录当前表数据的数据条数据类型_mysql的表的操作 数据类型

一 数据类型1 数字&#xff1a;整型&#xff1a;tinyint int bigint小数&#xff1a;float:在位数较短的情况下不精准double:在位数比较长的情况下不精准1 数字整型&#xff1a;tinyint int big小数&#xff1a;float:在位数比较短的情况下不精准double:在位数比较长的…

C++中的继承与虚函数各种概念

虚继承与一般继承 虚继承和一般的继承不同&#xff0c;一般的继承&#xff0c;在目前大多数的C编译器实现的对象模型中&#xff0c;派生类对象会直接包含基类对象的字段。而虚继承的情况&#xff0c;派生类对象不会直接包含基类对象的字段&#xff0c;而是通过一个间接的指针去…

中国科学院大学数学院本科生教材

中国科学院大学数学科学学院本科生教材&#xff08;不完全统计&#xff09; 注&#xff1a;不同的任课老师使用不太一样的教材&#xff0c;仅供参考。 一年级&#xff1a; 微积分I-A&#xff1a;《数学分析&#xff08;第4版&#xff09;》第1卷&#xff0c;卓里奇&#xff0c;…

sqlite mysql php_PHP实现的简单操作SQLite数据库类与用法示例

本文实例讲述了PHP实现的简单操作SQLite数据库类与用法。分享给大家供大家参考&#xff0c;具体如下&#xff1a;SQLite是一款轻型的数据库&#xff0c;是遵守ACID的关联式数据库管理系统&#xff0c;它的设计目标是嵌入式的&#xff0c;而且目前已经在很多嵌入式产品中使用了它…

Win7下WinDbg开启Local Kernel Debug调试

问题&#xff1a;在Win7 64bit系统中用管理员权限打开WinDbg开启Local Kernel Debug时报错&#xff1a; The system does not support local kernel debugging. Local kernel debugging requires Windows XP, Administrative privileges, and is not supported by WOW64. Only …

idea 不能及时编译_您是否能及时编译?

idea 不能及时编译还记得上次被C开发人员嘲笑的时候吗&#xff1f; Java如此繁琐&#xff0c;以至于他们甚至都不会考虑使用这种语言&#xff1f; 在许多方面&#xff0c;这一概念仍然成立。 但是对于典型的用法&#xff08;在大型企业的骨干中&#xff09;&#xff0c;Java性…