Apache Felix 上的 OSGi 部署
OSGi deployment on Apache Felix
我已经创建了我的第一个 OSGi 服务,并试图将其部署到 Apache Felix 上。事后查看系统控制台时,发现服务未激活,出现了一些问题:
org.springframework.ws.client.core,version=[2.1,3) -- Cannot be resolved
org.springframework.ws.soap,version=[2.1,3) -- Cannot be resolved
org.springframework.ws.soap.axiom,version=[2.1,3) -- Cannot be resolved
org.springframework.ws.soap.saaj,version=[2.1,3) -- Cannot be resolved
所以我查看了哪个 jar 包含这些包,这来自 spring-ws-core-2.1.2.RELEASE.jar,它也是一个 OSGi 包。我也部署了那个,但随后再次出现以下错误消息:
org.springframework.web.servlet,version=[3.1.0, 4.0.0) -- Cannot be resolved
再次依赖,这次是 spring-webmvc-3.2.17.RELEASE.jar。然而问题是这个不是 OSGi 包,那么我该如何解决这个问题呢?因为是第三方库所以能想到的不多
那么如何在 OSGi 容器中使用非 bundle jar?
我怎样才能自动解决依赖关系树而不必手动解决所有问题?
我创建了 osgi-run 项目来解决使用标准 Maven 依赖项解析(而不是未得到广泛支持的 OBR,不幸的是)解决捆绑包依赖项的问题,由 Gradle 支持.
但是,Spring jar 是一个可怕的噩梦,因为 Spring 项目在几年前放弃了对 OSGi 的支持。
理论上,使用 osgi-运行,您应该能够使用以下 gradle 文件创建包含 spring-ws-core 包的 OSGi 环境:
plugins {
id "com.athaydes.osgi-run" version "1.5.1"
}
repositories {
mavenLocal()
jcenter()
}
dependencies {
osgiRuntime 'org.springframework.ws:spring-ws-core:2.1.1.RELEASE'
}
这取决于poms中的信息是否一致。如果找到任何非包,它会自动转换为 OSGi 包(参见 wrapping jars)。
但是,这不起作用...Gradle 可以打印 spring-ws-core jar 的依赖层次结构,这是我使用它时得到的结果:
+--- org.springframework.ws:spring-ws-core:2.1.1.RELEASE
| +--- org.springframework.ws:spring-xml:2.1.1.RELEASE
| | +--- org.springframework:spring-context:3.1.2.RELEASE
| | | +--- org.springframework:spring-aop:3.1.2.RELEASE
| | | | +--- aopalliance:aopalliance:1.0
| | | | +--- org.springframework:spring-asm:3.1.2.RELEASE
| | | | +--- org.springframework:spring-beans:3.1.2.RELEASE
| | | | | \--- org.springframework:spring-core:3.1.2.RELEASE
| | | | | +--- org.springframework:spring-asm:3.1.2.RELEASE
| | | | | \--- commons-logging:commons-logging:1.1.1
| | | | \--- org.springframework:spring-core:3.1.2.RELEASE (*)
| | | +--- org.springframework:spring-beans:3.1.2.RELEASE (*)
| | | +--- org.springframework:spring-core:3.1.2.RELEASE (*)
| | | +--- org.springframework:spring-expression:3.1.2.RELEASE
| | | | \--- org.springframework:spring-core:3.1.2.RELEASE (*)
| | | \--- org.springframework:spring-asm:3.1.2.RELEASE
| | +--- commons-logging:commons-logging:1.1.1
| | +--- org.springframework:spring-core:3.1.2.RELEASE (*)
| | \--- org.springframework:spring-beans:3.1.2.RELEASE (*)
| +--- org.springframework:spring-context:3.1.2.RELEASE (*)
| +--- org.springframework:spring-aop:3.1.2.RELEASE (*)
| +--- org.springframework:spring-oxm:3.1.2.RELEASE
| | +--- commons-lang:commons-lang:2.5
| | +--- org.springframework:spring-beans:3.1.2.RELEASE (*)
| | +--- org.springframework:spring-context:3.1.2.RELEASE (*)
| | \--- org.springframework:spring-core:3.1.2.RELEASE (*)
| +--- org.springframework:spring-web:3.1.2.RELEASE
| | +--- aopalliance:aopalliance:1.0
| | +--- org.springframework:spring-beans:3.1.2.RELEASE (*)
| | +--- org.springframework:spring-context:3.1.2.RELEASE (*)
| | \--- org.springframework:spring-core:3.1.2.RELEASE (*)
| +--- org.springframework:spring-webmvc:3.1.2.RELEASE
| | +--- org.springframework:spring-asm:3.1.2.RELEASE
| | +--- org.springframework:spring-beans:3.1.2.RELEASE (*)
| | +--- org.springframework:spring-context:3.1.2.RELEASE (*)
| | +--- org.springframework:spring-context-support:3.1.2.RELEASE
| | | +--- org.springframework:spring-beans:3.1.2.RELEASE (*)
| | | +--- org.springframework:spring-context:3.1.2.RELEASE (*)
| | | \--- org.springframework:spring-core:3.1.2.RELEASE (*)
| | +--- org.springframework:spring-core:3.1.2.RELEASE (*)
| | +--- org.springframework:spring-expression:3.1.2.RELEASE (*)
| | \--- org.springframework:spring-web:3.1.2.RELEASE (*)
| +--- wsdl4j:wsdl4j:1.6.1
| +--- commons-logging:commons-logging:1.1.1
| +--- org.springframework:spring-core:3.1.2.RELEASE (*)
| \--- org.springframework:spring-beans:3.1.2.RELEASE (*)
我认为依赖解析中可能存在一些错误,因为根据上面解析的依赖关系图,似乎 Spring 2 个 jar 与 Spring 3 个 jar 混在一起了!但是不...是 exactly right.
但无论如何,经过一些调查后我开始工作了...
正在调查未满足的捆绑包要求
首先,我注意到 Spring AOP 没有解决,因为它的 org.aopalliance.aop
要求。
显然,这应该来自 aopalliance jar(它不是一个包,至少不是 Maven Central/JCenter 中的包)。
我在 Gradle 文件的 runOsgi
块中添加了这条指令,这样我就可以看到 osgi-run
如何将 jar 打包成一个包:
wrapInstructions {
printManifests = true
}
运行 gradle clean createOsgi
再次打印清单...它看起来像这样:
--------------------------------- Manifest for aopalliance-1.0.jar ---------------------------------
Manifest-Version: 1.0
Bundle-SymbolicName: aopalliance
Bundle-ManifestVersion: 2
Bnd-LastModified: 1474120107912
Import-Package: org.aopalliance.aop
Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=1.3))"
Tool: Bnd-3.1.0.201512181341
Ant-Version: Apache Ant 1.5.4
Originally-Created-By: 1.4.2_01-b06 (Sun Microsystems Inc.)
Export-Package: org.aopalliance.aop,org.aopalliance.intercept;uses:="o
rg.aopalliance.aop"
Bundle-Version: 1.0.0
Bundle-Name: aopalliance
Created-By: 1.8.0_60 (Oracle Corporation)
----------------------------------------------------------------------------------------------------
请注意,有一个正确生成的 Bundle-Version
,但包未使用该版本导出...通过添加以下指令,我们可以强制使用以下版本导出包:
wrapInstructions {
printManifests = true
manifest( 'aopalliance.*' ) {
instruction 'Export-Package', '*;version=1.0'
}
}
现在,清单中的 Export-Package
指令是正确的:
Export-Package: org.aopalliance.aop;version="1.0",org.aopalliance.inte
rcept;version="1.0";uses:="org.aopalliance.aop"
和运行连接OSGi容器,我们看到Spring AOP bundle仍然没有解析,但现在唯一的问题是因为它的(&(osgi.wiring.package=org.apache.commons.logging)(version>=1.1.1)(!(version>=2.0.0)))
要求不满足。
commons.logging
jar 有一个已知问题(documented 在 osgi-run
README 页面)...它声明了可选的依赖项,使其难以自动包装。
但另外,commons.logging
jar 在清单中有一个不正确的 Specification-Version
。它说 1.0
而不是 1.1.1
,这就是 osgi-run
用于捆绑版本的内容,因此 Bundle-Version
得到了不正确的值。
通过强制 osgi-run
导出具有正确版本的包,包装工作正常并且 Spring AOP 正确启动:
manifest( /commons-logging.*/ ) {
instruction 'Import-Package', '!javax.servlet,!org.apache.*,*'
instruction 'Export-Package', '*;version=1.1.1'
}
现在,转到下一个问题,我们注意到 org.springframework.web
没有解决,因为它对 (&(osgi.wiring.package=javax.servlet)(version>=2.4.0)(!(version>=4.0.0)))
的要求。
这个很简单,将 servlet-api 包(由 Felix 提供)添加到 OSGi 运行time,它应该可以工作...只需在 Gradle 文件:
osgiRuntime 'org.apache.felix:org.apache.felix.http.servlet-api:1.1.2'
现在,OSGi 环境启动没有任何故障!
最终解决方案
这是安装的全套捆绑包:
ID|State |Level|Name
0|Active | 0|System Bundle (5.4.0)|5.4.0
1|Active | 1|aopalliance (1.0.0)|1.0.0
2|Active | 1|Commons Lang (2.5.0)|2.5.0
3|Active | 1|Jakarta Commons Logging (1.0.0)|1.0.0
4|Active | 1|Apache Felix Gogo Command (0.16.0)|0.16.0
5|Active | 1|Apache Felix Gogo Runtime (0.16.2)|0.16.2
6|Active | 1|Apache Felix Gogo Shell (0.12.0)|0.12.0
7|Active | 1|Apache Felix Servlet API (1.1.2)|1.1.2
8|Active | 1|Spring AOP (3.1.2.RELEASE)|3.1.2.RELEASE
9|Active | 1|Spring ASM (3.1.2.RELEASE)|3.1.2.RELEASE
10|Active | 1|Spring Beans (3.1.2.RELEASE)|3.1.2.RELEASE
11|Active | 1|Spring Context (3.1.2.RELEASE)|3.1.2.RELEASE
12|Active | 1|Spring Context Support (3.1.2.RELEASE)|3.1.2.RELEASE
13|Active | 1|Spring Core (3.1.2.RELEASE)|3.1.2.RELEASE
14|Active | 1|Spring Expression Language (3.1.2.RELEASE)|3.1.2.RELEASE
15|Active | 1|Spring Object/XML Mapping (3.1.2.RELEASE)|3.1.2.RELEASE
16|Active | 1|Spring Web (3.1.2.RELEASE)|3.1.2.RELEASE
17|Active | 1|Spring Web Servlet (3.1.2.RELEASE)|3.1.2.RELEASE
18|Active | 1|Spring Web Services Core (2.1.1.RELEASE)|2.1.1.RELEASE
19|Active | 1|Spring XML (2.1.1.RELEASE)|2.1.1.RELEASE
20|Active | 1|tomcat-servlet-api (8.0.0)|8.0.0
21|Active | 1|JWSDL (1.2.0)|1.2.0
如果您想尝试 osgi-run
,这是我使用的 Gradle 文件:
plugins {
id "com.athaydes.osgi-run" version "1.5.1"
}
repositories {
mavenLocal()
jcenter()
}
dependencies {
osgiRuntime 'org.springframework.ws:spring-ws-core:2.1.1.RELEASE'
osgiRuntime 'org.apache.felix:org.apache.felix.http.servlet-api:1.1.2'
}
runOsgi {
wrapInstructions {
printManifests = true
manifest( 'aopalliance.*' ) {
instruction 'Export-Package', '*;version=1.0'
}
manifest( /commons-logging.*/ ) {
instruction 'Import-Package', '!javax.servlet,!org.apache.*,*'
instruction 'Export-Package', '*;version=1.1.1'
}
}
}
只需将其保存在 build.gradle
文件中,然后 运行 gradle createOsgi
即可在 build/osgi/run.sh
.
处获取您的入门脚本
我会努力 osgi-run
来尝试让这些事情自动解决,希望在下一个版本中,上面显示的第一个构建文件可以毫不费力地工作。
我已经创建了我的第一个 OSGi 服务,并试图将其部署到 Apache Felix 上。事后查看系统控制台时,发现服务未激活,出现了一些问题:
org.springframework.ws.client.core,version=[2.1,3) -- Cannot be resolved
org.springframework.ws.soap,version=[2.1,3) -- Cannot be resolved
org.springframework.ws.soap.axiom,version=[2.1,3) -- Cannot be resolved
org.springframework.ws.soap.saaj,version=[2.1,3) -- Cannot be resolved
所以我查看了哪个 jar 包含这些包,这来自 spring-ws-core-2.1.2.RELEASE.jar,它也是一个 OSGi 包。我也部署了那个,但随后再次出现以下错误消息:
org.springframework.web.servlet,version=[3.1.0, 4.0.0) -- Cannot be resolved
再次依赖,这次是 spring-webmvc-3.2.17.RELEASE.jar。然而问题是这个不是 OSGi 包,那么我该如何解决这个问题呢?因为是第三方库所以能想到的不多
那么如何在 OSGi 容器中使用非 bundle jar? 我怎样才能自动解决依赖关系树而不必手动解决所有问题?
我创建了 osgi-run 项目来解决使用标准 Maven 依赖项解析(而不是未得到广泛支持的 OBR,不幸的是)解决捆绑包依赖项的问题,由 Gradle 支持.
但是,Spring jar 是一个可怕的噩梦,因为 Spring 项目在几年前放弃了对 OSGi 的支持。
理论上,使用 osgi-运行,您应该能够使用以下 gradle 文件创建包含 spring-ws-core 包的 OSGi 环境:
plugins {
id "com.athaydes.osgi-run" version "1.5.1"
}
repositories {
mavenLocal()
jcenter()
}
dependencies {
osgiRuntime 'org.springframework.ws:spring-ws-core:2.1.1.RELEASE'
}
这取决于poms中的信息是否一致。如果找到任何非包,它会自动转换为 OSGi 包(参见 wrapping jars)。
但是,这不起作用...Gradle 可以打印 spring-ws-core jar 的依赖层次结构,这是我使用它时得到的结果:
+--- org.springframework.ws:spring-ws-core:2.1.1.RELEASE
| +--- org.springframework.ws:spring-xml:2.1.1.RELEASE
| | +--- org.springframework:spring-context:3.1.2.RELEASE
| | | +--- org.springframework:spring-aop:3.1.2.RELEASE
| | | | +--- aopalliance:aopalliance:1.0
| | | | +--- org.springframework:spring-asm:3.1.2.RELEASE
| | | | +--- org.springframework:spring-beans:3.1.2.RELEASE
| | | | | \--- org.springframework:spring-core:3.1.2.RELEASE
| | | | | +--- org.springframework:spring-asm:3.1.2.RELEASE
| | | | | \--- commons-logging:commons-logging:1.1.1
| | | | \--- org.springframework:spring-core:3.1.2.RELEASE (*)
| | | +--- org.springframework:spring-beans:3.1.2.RELEASE (*)
| | | +--- org.springframework:spring-core:3.1.2.RELEASE (*)
| | | +--- org.springframework:spring-expression:3.1.2.RELEASE
| | | | \--- org.springframework:spring-core:3.1.2.RELEASE (*)
| | | \--- org.springframework:spring-asm:3.1.2.RELEASE
| | +--- commons-logging:commons-logging:1.1.1
| | +--- org.springframework:spring-core:3.1.2.RELEASE (*)
| | \--- org.springframework:spring-beans:3.1.2.RELEASE (*)
| +--- org.springframework:spring-context:3.1.2.RELEASE (*)
| +--- org.springframework:spring-aop:3.1.2.RELEASE (*)
| +--- org.springframework:spring-oxm:3.1.2.RELEASE
| | +--- commons-lang:commons-lang:2.5
| | +--- org.springframework:spring-beans:3.1.2.RELEASE (*)
| | +--- org.springframework:spring-context:3.1.2.RELEASE (*)
| | \--- org.springframework:spring-core:3.1.2.RELEASE (*)
| +--- org.springframework:spring-web:3.1.2.RELEASE
| | +--- aopalliance:aopalliance:1.0
| | +--- org.springframework:spring-beans:3.1.2.RELEASE (*)
| | +--- org.springframework:spring-context:3.1.2.RELEASE (*)
| | \--- org.springframework:spring-core:3.1.2.RELEASE (*)
| +--- org.springframework:spring-webmvc:3.1.2.RELEASE
| | +--- org.springframework:spring-asm:3.1.2.RELEASE
| | +--- org.springframework:spring-beans:3.1.2.RELEASE (*)
| | +--- org.springframework:spring-context:3.1.2.RELEASE (*)
| | +--- org.springframework:spring-context-support:3.1.2.RELEASE
| | | +--- org.springframework:spring-beans:3.1.2.RELEASE (*)
| | | +--- org.springframework:spring-context:3.1.2.RELEASE (*)
| | | \--- org.springframework:spring-core:3.1.2.RELEASE (*)
| | +--- org.springframework:spring-core:3.1.2.RELEASE (*)
| | +--- org.springframework:spring-expression:3.1.2.RELEASE (*)
| | \--- org.springframework:spring-web:3.1.2.RELEASE (*)
| +--- wsdl4j:wsdl4j:1.6.1
| +--- commons-logging:commons-logging:1.1.1
| +--- org.springframework:spring-core:3.1.2.RELEASE (*)
| \--- org.springframework:spring-beans:3.1.2.RELEASE (*)
我认为依赖解析中可能存在一些错误,因为根据上面解析的依赖关系图,似乎 Spring 2 个 jar 与 Spring 3 个 jar 混在一起了!但是不...是 exactly right.
但无论如何,经过一些调查后我开始工作了...
正在调查未满足的捆绑包要求
首先,我注意到 Spring AOP 没有解决,因为它的 org.aopalliance.aop
要求。
显然,这应该来自 aopalliance jar(它不是一个包,至少不是 Maven Central/JCenter 中的包)。
我在 Gradle 文件的 runOsgi
块中添加了这条指令,这样我就可以看到 osgi-run
如何将 jar 打包成一个包:
wrapInstructions {
printManifests = true
}
运行 gradle clean createOsgi
再次打印清单...它看起来像这样:
--------------------------------- Manifest for aopalliance-1.0.jar ---------------------------------
Manifest-Version: 1.0
Bundle-SymbolicName: aopalliance
Bundle-ManifestVersion: 2
Bnd-LastModified: 1474120107912
Import-Package: org.aopalliance.aop
Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=1.3))"
Tool: Bnd-3.1.0.201512181341
Ant-Version: Apache Ant 1.5.4
Originally-Created-By: 1.4.2_01-b06 (Sun Microsystems Inc.)
Export-Package: org.aopalliance.aop,org.aopalliance.intercept;uses:="o
rg.aopalliance.aop"
Bundle-Version: 1.0.0
Bundle-Name: aopalliance
Created-By: 1.8.0_60 (Oracle Corporation)
----------------------------------------------------------------------------------------------------
请注意,有一个正确生成的 Bundle-Version
,但包未使用该版本导出...通过添加以下指令,我们可以强制使用以下版本导出包:
wrapInstructions {
printManifests = true
manifest( 'aopalliance.*' ) {
instruction 'Export-Package', '*;version=1.0'
}
}
现在,清单中的 Export-Package
指令是正确的:
Export-Package: org.aopalliance.aop;version="1.0",org.aopalliance.inte
rcept;version="1.0";uses:="org.aopalliance.aop"
和运行连接OSGi容器,我们看到Spring AOP bundle仍然没有解析,但现在唯一的问题是因为它的(&(osgi.wiring.package=org.apache.commons.logging)(version>=1.1.1)(!(version>=2.0.0)))
要求不满足。
commons.logging
jar 有一个已知问题(documented 在 osgi-run
README 页面)...它声明了可选的依赖项,使其难以自动包装。
但另外,commons.logging
jar 在清单中有一个不正确的 Specification-Version
。它说 1.0
而不是 1.1.1
,这就是 osgi-run
用于捆绑版本的内容,因此 Bundle-Version
得到了不正确的值。
通过强制 osgi-run
导出具有正确版本的包,包装工作正常并且 Spring AOP 正确启动:
manifest( /commons-logging.*/ ) {
instruction 'Import-Package', '!javax.servlet,!org.apache.*,*'
instruction 'Export-Package', '*;version=1.1.1'
}
现在,转到下一个问题,我们注意到 org.springframework.web
没有解决,因为它对 (&(osgi.wiring.package=javax.servlet)(version>=2.4.0)(!(version>=4.0.0)))
的要求。
这个很简单,将 servlet-api 包(由 Felix 提供)添加到 OSGi 运行time,它应该可以工作...只需在 Gradle 文件:
osgiRuntime 'org.apache.felix:org.apache.felix.http.servlet-api:1.1.2'
现在,OSGi 环境启动没有任何故障!
最终解决方案
这是安装的全套捆绑包:
ID|State |Level|Name
0|Active | 0|System Bundle (5.4.0)|5.4.0
1|Active | 1|aopalliance (1.0.0)|1.0.0
2|Active | 1|Commons Lang (2.5.0)|2.5.0
3|Active | 1|Jakarta Commons Logging (1.0.0)|1.0.0
4|Active | 1|Apache Felix Gogo Command (0.16.0)|0.16.0
5|Active | 1|Apache Felix Gogo Runtime (0.16.2)|0.16.2
6|Active | 1|Apache Felix Gogo Shell (0.12.0)|0.12.0
7|Active | 1|Apache Felix Servlet API (1.1.2)|1.1.2
8|Active | 1|Spring AOP (3.1.2.RELEASE)|3.1.2.RELEASE
9|Active | 1|Spring ASM (3.1.2.RELEASE)|3.1.2.RELEASE
10|Active | 1|Spring Beans (3.1.2.RELEASE)|3.1.2.RELEASE
11|Active | 1|Spring Context (3.1.2.RELEASE)|3.1.2.RELEASE
12|Active | 1|Spring Context Support (3.1.2.RELEASE)|3.1.2.RELEASE
13|Active | 1|Spring Core (3.1.2.RELEASE)|3.1.2.RELEASE
14|Active | 1|Spring Expression Language (3.1.2.RELEASE)|3.1.2.RELEASE
15|Active | 1|Spring Object/XML Mapping (3.1.2.RELEASE)|3.1.2.RELEASE
16|Active | 1|Spring Web (3.1.2.RELEASE)|3.1.2.RELEASE
17|Active | 1|Spring Web Servlet (3.1.2.RELEASE)|3.1.2.RELEASE
18|Active | 1|Spring Web Services Core (2.1.1.RELEASE)|2.1.1.RELEASE
19|Active | 1|Spring XML (2.1.1.RELEASE)|2.1.1.RELEASE
20|Active | 1|tomcat-servlet-api (8.0.0)|8.0.0
21|Active | 1|JWSDL (1.2.0)|1.2.0
如果您想尝试 osgi-run
,这是我使用的 Gradle 文件:
plugins {
id "com.athaydes.osgi-run" version "1.5.1"
}
repositories {
mavenLocal()
jcenter()
}
dependencies {
osgiRuntime 'org.springframework.ws:spring-ws-core:2.1.1.RELEASE'
osgiRuntime 'org.apache.felix:org.apache.felix.http.servlet-api:1.1.2'
}
runOsgi {
wrapInstructions {
printManifests = true
manifest( 'aopalliance.*' ) {
instruction 'Export-Package', '*;version=1.0'
}
manifest( /commons-logging.*/ ) {
instruction 'Import-Package', '!javax.servlet,!org.apache.*,*'
instruction 'Export-Package', '*;version=1.1.1'
}
}
}
只需将其保存在 build.gradle
文件中,然后 运行 gradle createOsgi
即可在 build/osgi/run.sh
.
我会努力 osgi-run
来尝试让这些事情自动解决,希望在下一个版本中,上面显示的第一个构建文件可以毫不费力地工作。