Apache Felix上的OSGi部署

时间:2016-09-09 07:01:01

标签: java deployment osgi 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容器中使用非捆绑jar? 如何自动解析依赖关系树而不必手动解决所有问题?

1 个答案:

答案 0 :(得分:1)

我已经创建了osgi-run项目,以解决使用标准Maven依赖项解析(不幸的是,不是广泛支持的OBR)解决捆绑依赖项的这个问题,Gradle支持。

然而,自从几年前Spring Project放弃了对OSGi的支持以来,Spring罐子是一个可怕的噩梦。

理论上,使用osgi-run,您应该能够使用以下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中的信息是否一致。如果找到任何非bundle,它会自动转换为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捆绑仍然无法解决,但现在唯一的问题是因为它的(&(osgi.wiring.package=org.apache.commons.logging)(version>=1.1.1)(!(version>=2.0.0)))要求不满意。

commons.logging jar有一个已知问题(osgi-run README页面中的documented)...它声明了可选的依赖关系,这使得很难自动换行。

但另外,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运行时,它应该可以工作......只需在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上尝试让这些事情自动解决,希望在下一个版本中,上面显示的第一个构建文件可以毫不费力地工作。