osgi笔记-程序员宅基地

Bundle-Classpath可以实现内嵌jar。

一个Bundle的Activator不需要进行Export

一个Package中的类被两个ClassLoader加载,包中的Private class对于两个ClassLoader之间是相互不可见的。

Manifest语法: name: value,我们称之为一个条目,Manifest文件有不受限制的条目个数,其中name是不区分大小写,可以包含字母数字,下划线,中划线,Value可以包含除子\r, \n之后的所有字符,name和value之间必须用一个冒号和一个空格分隔开,一行不能超过72个字符,超过72字符部分需要从下一行,以一个空格开始继续写,

Manifest中空行或者全是空格的行用来划分属性group。osgi只取第一个group中定义的name value。

Osgi Manifest的条目定义形式如下,value中有多个clause(用","分隔),每个clause中包含有target,directive和attribute三部分。其具体语法请参考OSGi In action一书或者OSGI规范。不过一般不需要纠结于这一点,看了下面的一些例子相信大部分读者都能“不攻自破”,但书面表达起来的确是个问题。

Property-Name: target1; dir1:=value1; attr1=value2,
 target2; dir1:=value1; attr1=value2,
 target3; dir1:=value1; attr1=value2

如果value中包含有空格或者分隔符“,” 和“;”的话,需要用括号来括起来

如果多个target之间有相同的attribute和directive的话,可以采用下面的简写形式:

Property-Name: target1; target2; dir1:=value1; attr1=value2

 

下面是一些human-readable bundle metadata。Osgi framework将它们忽略:需要注意的是由于历史原因Bundle-Name并不是一个用于Bundle Identification的Manifest Attribute。

Bundle-Name: Simple Paint API                              
Bundle-Description: Public API for a simple paint program. 
Bundle-DocURL: http://www.manning.com/osgi-in-action/      
Bundle-Category: example, library                          
Bundle-Vendor: OSGi in Action                              
Bundle-ContactAddress: 1234 Main Street, USA               
Bundle-Copyright: OSGi in Action                     

 

Bundle-SymbolicName和Bundle-Version用于唯一标识一个Bundle。它们在Require-Bundle中被使用,大多数情况下,osgi还是在使用package作为import的标识的。

Bundle-SymblicName的value类似于java的包名,用"."来分隔。Bundle-Version的value遵循osgi version的命名规则

例如:

Bundle-ManifestVersion: 2 // 这个也会起标识作用,但目前它仅有2是合法的。
Bundle-SymbolicName: org.foo.shape
Bundle-Version: 2.0.0

 

Osgi中关于代码可见性的metadata有以下几种信息:这里不作翻译,直接贴上书中的原文:

Internal bundle class path:  The code forming the bundle
Exported internal code:       Explicitly exposed code from the bundle class path for sharing with other bundles
Imported external code:       External code on which the bundle class path code depends

 

Bundle-ClassPath用于表示Bundle内部类加载时的ClassPath,类似于定义内部可见性,注意这些ClassPath都是相对于Bundle jar文件内部的,我们还可以在Bundle中加入内嵌的jar包,如下:

Bundle-ClassPath: .,other-classes/,embedded.jar

Bundle-ClassPath的缺省值是".",也就和非osgi环境中的jar包的加载规则一致了。

Export-Package用于暴露bundle内部的类,多个包名之间用逗号隔开","同时,包名可以用";"隔开并加上限定的Attribute,因此多个Bundle可能导出同样的包名,这时候需要其它信息加以限定,并且如果多个包名所有的限定属性都一致的话,采用采用省略的写法,如下:

Export-Package: org.foo.shape; vendor="Manning", org.foo.other;
 vendor="Manning"
和下面的写法效果一致
Export-Package: org.foo.shape; org.foo.other; vendor="Manning"

除此之外,osgi定义了一个专门的限定属性version,其值必须遵循osgi version的规范。另外包名下的子包是不会被导出的。

 

Import-Package用于导入在运行时bundle所依赖的类。但java.*开头的类比较特殊,它自动地对所有的bundle都是可见的,因此我们不需要也无法插手这一点。Import-Package和Export-Package的写法上基本一致,但是Import-Package可以指定version的范围,比如:

Import-Package: org.osgi.framework; version="[1.3.0,2.0.0)"

version定义规范如下:

在没有version限定的情况下,version默认为0.0.0,因此version>=0.0.0的匹配到的包都有可能被选择。

1、注意在有多个版本的Export-Package符合version要求的话,那么osgi将会选择最高版本那个,比如servlet bundle提供javax.servlet; version="2.4.0"而tomcat bundle提供了javax.servlet; version="2.5",那么osgi将使用tomcat中提供的类。如果servlet bundle已经先于tomcat bundle被使用,那么将使用servlet bundle中的类,即使它的版本号比较低。

2、如果有两个bundle提供的版本号也相同的话,那么选择,最先被install的那个bundle。

Use directive:上面两点在解决类不一致问题上还是不足的,对于在方法名上暴露了import进来的类的情况下(osgi in action page61-63),需要用uses:=import.package.name这一条directive来解决,uses:=import.package.name用于保证其它bundle import这个bundle的Export-Package的时候,转为使用这个Bundle所import的import.package.name,上面这句话不知道怎么表达哈,贴上原书的图:

其实Http Service这个Bundle在Export-Package中,通过方法的签名暴露了从Servlet API bundle import进来的javax.servlet.Servlet和javax.servlet.ServletContext:

package org.osgi.service.http; 
import javax.servlet.Servlet; 
public interface HttpService {
  void registerServlet(Sting alias, Servlet servlet, HttpContext ctx); 
}

那么在Http Servlet Bundle中使用uses:=javax.servlet时候,将传递性地使Http Client也转为使用Servlet API Bundle中export的javax.servlet; version="2.3.0",从而保证了类的一致性:

Export-Package: org.osgi.service.http;
 uses:="javax.servlet"; version="1.0.0"
Import-Package: javax.servlet; version="2.3.0"

不过osgi framework并不能为我们解决所有的问题,所以这种情况下我们自己可以手动解决的就不要偷懒了。

 

类搜索的顺序:

1、如果类名以java.开头,那调用父加载器进行加载,如果找不到将抛出ClassNotFoundException等异常。

2、如果这个类属于Import-Package中的一员,那么,委托给对应的外部的Bundle进行加载。

3、最后搜索Bundle-ClassPath

 关于osgi模块化的高级特性:

importing exported packages, implicit attributes, mandatory attributes, class filtering, and duplicate exports.

Importing exported packages: 这种情况多发生在接口与实现打包在一起,而又希望osgi环境中可以从别的bundle中拿到接口的实现者,而且它们之间可以进行交互。比如书中所描述的情况:
Bundle A, Bundle B 都导出了javax.servlet,Bundle A import javax.servlet.Servlet,而且A在使用javax.servlet.Servlet时候希望能同时在B和C之间传递,交互。

那么,针对C有两种解决方案:

1、删除C中的javax.servlet,import B中的。

2、不删除C中的,并且导出javax.servlet。

方案1的话,C将依赖于B,在缺少B的环境将无法使用。

方案2的话,A中的javax.servlet.Servlet无法在B,C之间传递,否则将引起ClassCastException。

针对这个情况,osgi提供了一个import exported package方案,我们可以在C中使用import exported package,如下,Import-Package 和Export-Package可以有不同的Version,表明C可以更低版本的javax.servlet下工作,这并不是错误:

Export-Package: javax.servlet; version="2.4.0"
Import-Package: javax.servlet; version="2.3.0"

 

Implicit export attribute Export-Package(隐性携带的属性):

在Export-Package的时候,OSGi framework隐性地在导入的包中附加上bundle-symbolic-name(值为Bundle-SymblicName)和bundle-version(值为Bundle-Version)属性:

Bundle-ManifestVersion: 2
Bundle-SymbolicName: my.javax.servlet
Bundle-Version: 1.2.0
Export-Package: javax.servlet; javax.servlet.http; version="2.4.0"

等同于(下面展示用,不能像下面直接在Manifest Export-Package中写bundle-symbolic-name和bundler-version属性,否则会在install bundle时候抛出异常)

Bundle-ManifestVersion: 2
Bundle-SymbolicName: my.javax.servlet
Bundle-Version: 1.2.0
Export-Package: javax.servlet; javax.servlet.http; version="2.4.0";
bundle-symbolic-name="my.javax.servlet"; bundle-version="1.2.0"

同时在Import-Package的时候指定bundle-symbolic-name和bundle-version:

Import-Package: javax.servlet; bundle-symbolic-name="my.javax.servlet"; bundle-version="[1.2.0,1.2.0]"

注意应该尽量避免implicit exported package,因为正常的Export-Package 属性也可以完成类似的工作。

Mandatory directive用于指定Export-Package中,Import-Package在进行bundle 匹配的时候必须进行匹配的属性,如果属性不存在或者匹配不上,那么将不会import 这个package。比如下面的例子:

Export-Package: javax.servlet; version="2.4.1"; private="true";
mandatory:="private"

那么在Import-Package的时候必须指定这个private属性才能import成功:

Import-Package: javax.servlet; version="[2.4.0,2.5.0)"; private=true

Exclude Directive用于从Export-Package中过滤掉(屏蔽)一些类,如下,org.foo.service.Util将不会被导出,Exclude Directive支持通配符*:

Export-Package: org.foo.service; version="1.0.0"; exclude:="Util"

同样Include Directive用于指定Export-Package中进行导出的类:

Export-Package: org.foo.service; version="1.0.0"; include:="Service*"

Duplicate Export和Include Directive, Export Directive结合用于实现向不同的bundle导出不同的类。

resolution directive用于表明依赖是可选的,在没有Bundle export相应的package情况下也能完成bundle resolve过程,ClassNotFoundException,找不到这些类的情况下该bundle 也可以正常完成工作,比如一些日志服务类。

Dynamic Import 用于解决SPI问题。

DynamicImport-Package: javax.servlet.*; version="2.4.0"

DynamicImport-Package和resolution:=optional有以下两点相同之处 :

Optional/dynamic imports never cause a bundle to be unable to resolve.
Your bundle code must be prepared to catch ClassNotFoundException s for the optionally/dynamically imported packages.

 

Require-Bundle: 用于导入另一个bundle中所有的Export-Package。

关于存在Require-Bundle时候的类搜索顺序:

1、如果类名以java.开头,那调用父加载器进行加载,如果找不到将抛出ClassNotFoundException等异常。

2、如果这个类属于Import-Package中的一员,那么,委托给对应的外部的Bundle进行加载。

3、如果这个类属于Require-Bundle中的,那么将从Require-Bundle目标中进行搜索,如果找到了即返回,如果没有找到则继续从下一个Require-Bundle目标开始搜索。

4、如果3中找不到的话,从Bundle-ClassPath中搜索。如果没有找到的话继续步骤5

5、如果类所在的包isn't exported or required(这里的意思不是很清楚)的话,开始对DynamicImport-Package进行匹配,如果匹配到了,则委托给export这个package的Bundle。如果找到了,则返回,如果最后还是找不到只好抛出异常了。

同样Require-Bundle也可以使用resolution:="optional" directive,并且可以使用visibility进行reexport,比如A require-bundle B那么B中的Export-Package将会添加在Bundle A的Export-Package列表中。

最后一个特性是Fragment Bundle,在Fragment Bundle中,有Host和Fragment两种角色,Host Bundle中对Fragment Bundle是不可知的,但Fragment Bundle中必须声明它所属于的Host Bundle(通过Fragment-Host):(注意只能声明一个Host Bundle,不能声明多个)

Fragment-Host: org.foo.hostbundle; bundle-version="[1.0.0,1.1.0)"

Host Bundle中无须声明任何关于Fragment Bundle的信息,没有Fragment-Host声明的Bundle默认就是一个Host Bundle。

另外Fragment Bundle中不能定义Bundle-Activator,因为它不是一个独立的bundle。它必须依存于Host Bundle。

注意,Fragment-Bundle和Host Bundle使用同一个ClassLoader

最终在查找类的时候的搜索顺序:

1、如果类名以java.开头,那调用父加载器进行加载,如果找不到将抛出ClassNotFoundException等异常。

2、如果这个类属于Import-Package中的一员,那么,委托给对应的外部的Bundle进行加载。

3、如果这个类属于Require-Bundle中的,那么将从Require-Bundle目标中进行搜索,如果找到了即返回,如果没有找到则继续从下一个Require-Bundle目标开始搜索。

4、如果3中找不到的话,从Bundle-ClassPath中搜索。如果没有找到的话继续步骤5

5、搜索已经installed的Fragment Bundle的Class path,如果查找到了则返回,如果没有找到则继续直到查找完所有的Fragment Bundle,如果最后仍然没有找到则开始步骤6

6、 如果类所在的包isn't exported or required(这里的意思不是很清楚)的话,开始对DynamicImport-Package进行匹配,如果匹配到了,则委托给export这个 package的Bundle。如果找到了,则返回,如果最后还是找不到只好抛出异常了。

转载于:https://www.cnblogs.com/mosmith/p/5465489.html

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_30871905/article/details/98532057

智能推荐

python色卡识别_用Python帮小姐姐选口红,人人都是李佳琦-程序员宅基地

文章浏览阅读502次。原标题:用Python帮小姐姐选口红,人人都是李佳琦 对于李佳琦,想必知道他的女生要远远多于男生,李佳琦最早由于直播向广大的网友们推荐口红,逐渐走红网络,被大家称作“口红一哥”。不可否认的是,李佳琦的直播能力确实很强,他能够抓住绝大多数人的心理,让大家喜欢看他的直播,看他直播推荐的口红适不适合自己,色号适合什么样子的妆容。为了提升效率,让自己的家人或者女友能够快速的挑选出合适自己妆容的口红色号,今..._获取口红品牌 及色号,色值api

linux awk命令NR详解,linux awk命令详解-程序员宅基地

文章浏览阅读3.6k次。简介awk命令的名称是取自三位创始人Alfred Aho 、Peter Weinberger 和 Brian Kernighan姓名的首字母,awk有自己的程序设计语言,设计简短的程序,读入文件,数据排序,处理数据,生成报表等功能。awk 通常用于文本处理和报表生成,最基本功能是在文件或者字符串中基于指定规则浏览和抽取信息,awk抽取信息后,才能进行其他文本操作。awk 通常以文件的一行为处理单位..._linux awk nr

android 网络连接失败!failed to connect to /192.168.1.186(port 8080)_failed to connect to 192.168.88.218:80-程序员宅基地

文章浏览阅读1.3w次,点赞5次,收藏2次。在网上找了一个小时,一直没有头绪,因为上个星期还是好好的,最后看到一个大神的解答,只需要将防火墙关闭就好了.原本向测试功能的,却卡在了登录上.以此记录.另外好像还有种错误是电脑与手机连接的WiFi不同,也可以看看...._failed to connect to 192.168.88.218:80

matlab 多径衰落,利用MATLAB仿真多径衰落信道.doc-程序员宅基地

文章浏览阅读1.9k次。利用MATLAB仿真多种多径衰落信道摘要:移动信道的多径传播引起的瑞利衰落,时延扩展以及伴随接收过程的多普勒频移使接受信号受到严重的衰落,阴影效应会是接受的的信号过弱而造成通信的中断:在信道中存在噪声和干扰,也会是接收信号失真而造成误码,所以通过仿真找到衰落的原因并采取一些信号处理技术来改善信号接收质量显得很重要,这里利用MATLAB对多径衰落信道的波形做一比较。一,多径衰落信道的特点关于多径衰落..._matlab多径衰落工具箱

python对json的操作及实例解析_import json灰色-程序员宅基地

文章浏览阅读1w次,点赞2次,收藏17次。Json简介:Json,全名 JavaScript Object Notation,是一种轻量级的数据交换格式。它基于 ECMAScript (w3c制定的js规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。 易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。(来自百度百科)python关于json文_import json灰色

mysql实现MHA高可用详细步骤_mysql mha超详细教程-程序员宅基地

文章浏览阅读1.1k次,点赞6次,收藏3次。一、工作原理MHA工作原理总结为以下几条:(1) 从宕机崩溃的 master 保存二进制日志事件(binlog events);(2) 识别含有最新更新的 slave ;(3) 应用差异的中继日志(relay log) 到其他 slave ;(4) 应用从 master 保存的二进制日志事件(binlog events);(5) 通过Manager控制器提升一个 slave 为新 m..._mysql mha超详细教程

随便推点

Linux环境下主从搭建心得(高手勿喷)_linux的java主从策略是什么-程序员宅基地

文章浏览阅读194次。一 java环境安装:1 安装JDK 参考链接地址:https://blog.csdn.net/qq_42815754/article/details/82968464注:有网情况下直接 yum 一键安装:yum -y list java(1)首先执行以下命令查看可安装的jdk版本(2)选择自己需要的jdk版本进行安装,比如这里安装1.8,执行以下命令:yum install -y java-1.8.0-openjdk-devel.x86_64(3)安装完之后,查看安装的jdk 版本,输入以下指令_linux的java主从策略是什么

ACM第四题_acm竞赛题 i 'm from mars-程序员宅基地

文章浏览阅读104次。定义int 类型,由while实现A,B的连续输入,输出A+B的值按Ctrl Z结束循环。#include<iostream>using namespace std;int main(){ int A,B; while(cin>>A>>B) { cout<<A+B<&_acm竞赛题 i 'm from mars

TextView.SetLinkMovementMethod后拦截所有点击事件的原因以及解决方法-程序员宅基地

文章浏览阅读5.2k次。在需要给TextView的某句话添加点击事件的时候,我们一般会使用ClickableSpan来进行富文本编辑。与此同时我们还需要配合 textView.setMovementMethod(LinkMovementMethod.getInstance());方法才能使点击处理生效。但与此同时还会有一个问题:如果我们给父布局添加一个点击事件,需要在点击非链接的时候触发(例如RectclerV..._linkmovementmethod

JAVA实现压缩解压文件_java 解压zip-程序员宅基地

文章浏览阅读1.1w次,点赞6次,收藏31次。JAVA实现压缩解压文件_java 解压zip

JDK8 新特性-Map对key和value分别排序实现_java comparingbykey-程序员宅基地

文章浏览阅读1.3w次,点赞7次,收藏21次。在Java 8 中使用Stream 例子对一个 Map 进行按照keys或者values排序.1. 快速入门 在java 8中按照此步骤对map进行排序.将 Map 转换为 Stream 对其进行排序 Collect and return a new LinkedHashMap (保持顺序)Map result = map.entrySet().stream() .sort..._java comparingbykey

GDKOI2021普及Day1总结-程序员宅基地

文章浏览阅读497次。第一次参加GDKOI,考完感觉还可以,结果发现还是不行,有一些地方细节打错,有些失分严重,总结出以下几点:1.大模拟一定要注意,细节打挂就是没分,像T1就是一道大模拟题,马上切了,后面就没想着检查以下,导致有些地方挂掉了,用民间数据一测,才85分。2.十年OI一场空,不开longlonglong longlonglong见祖宗。今天的T2本来想用暴力水点分的,结果没想到longlong→intlong long\to intlonglong→int,40→040\to040→0。3.代码实现能力太差,_gdkoi

推荐文章

热门文章

相关标签