如何在OSGI框架中的Runtime动态加载Java类?

时间:2012-03-15 06:47:31

标签: java osgi

我们正在项目中执行POC,我们在其中发送基于SOAP的请求,并相应地从Web服务获取SOAP响应。我们的目标是在我们的应用程序中利用spring框架提供的webservices模板(客户端API)。根据我们的架构,我们创建一个OSGI兼容的包(对于我们使用webservices模板API与Web服务交互的代码),然后将其部署到Apache Felix容器中。我们还在Felix容器中安装了所有依赖于OSGI的捆绑包,以便解决所有依赖关系。

根据webservices模板,默认Web服务消息发送方是HttpUrlConnectionMessageSender,它由类加载器在运行时动态加载。根据我的理解,我们得到以下异常,因为Felix容器无法从依赖的OSGI包加载类(Web服务包包含HttpUrlConnectionMessageSender)。请参阅下面的例外日志。

* org.springframework.beans.factory.BeanInitializationException: Could not find default strategy class for interface [org.springframework.ws.transport.WebServiceMessageSender]; nested exception is java.lang.ClassNotFoundException:org.springframework.ws.transport.http.HttpUrlConnectionMessageSender at  org.springframework.ws.support.DefaultStrategiesHelper.getDefaultStrategies(DefaultStrategiesHelper.java:126)

    at org.springframework.ws.support.DefaultStrategiesHelper.getDefaultStrategies(DefaultStrategiesHelper.java:90)

    at org.springframework.ws.client.core.WebServiceTemplate.initMessageSenders(WebServiceTemplate.java:320)

    at org.springframework.ws.client.core.WebServiceTemplate.initDefaultStrategies(WebServiceTemplate.java:306)

    at org.springframework.ws.client.core.WebServiceTemplate.<init>(WebServiceTemplate.java:143)

    at test.soapservice.service.SOAPServiceImpl.<init>(SOAPServiceImpl.java:40)

    at test.soapservice.service.SOAPServiceActivator.start(SOAPServiceActivator.java:17)

    at org.apache.felix.framework.util.SecureAction.startActivator(SecureAction.java:641)

    at org.apache.felix.framework.Felix.activateBundle(Felix.java:1977)

    at org.apache.felix.framework.Felix.startBundle(Felix.java:1895)

    at org.apache.felix.framework.BundleImpl.start(BundleImpl.java:944)

    at org.apache.felix.gogo.command.Basic.start(Basic.java:729)

引起:java.lang.ClassNotFoundException:org.springframework.ws.transport.http.HttpUrlConnectionMessageSender

    at java.net.URLClassLoader$1.run(URLClassLoader.java:200)

    at java.security.AccessController.doPrivileged(Native Method)

    at java.net.URLClassLoader.findClass(URLClassLoader.java:188)

    at java.lang.ClassLoader.loadClass(ClassLoader.java:307)

    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:268)

    at java.lang.ClassLoader.loadClass(ClassLoader.java:252)

    at org.springframework.util.ClassUtils.forName(ClassUtils.java:211)

    at org.springframework.util.ClassUtils.forName(ClassUtils.java:164)

    at org.springframework.ws.support.DefaultStrategiesHelper.getDefaultStrategies(DefaultStrategiesHelper.java:114)

根据我的理解,Felix容器无法使用存在于另一个bundle中的ClassUtils.forName()动态加载该类。我认为这是一个协作问题,当前的bundle有一个不同的类加载器,而不是依赖bundle的类加载器。

来自此社区的人是否遇到过同样的例外?如果是,那么您采取了哪些措施来解决运行时类依赖关系?请分享您的想法/指示以解决上述问题。快速回复将受到高度赞赏,可能有助于我们使POC成功。

提前致谢, Mridul Chopra

1 个答案:

答案 0 :(得分:0)

Class.forName()形式的类加载在任何OSGi容器中都不是问题。这里的问题是MANIFEST.MF文件不包含正确的导入声明。一个捆绑包应导出org.springframework.ws.transport包,而捆绑包应导入相同的包。

如果您使用Maven构建捆绑包,则可以使用Felix Bundle Plugin生成正确的清单信息。

<plugins>
  <plugin>
    <groupId>org.apache.felix</groupId>
    <artifactId>maven-bundle-plugin</artifactId>
    <extensions>true</extensions>
    <configuration>
      <instructions>
        <Private-Package>my.private.package.*</Private-Package>
      </instructions>
    </configuration>
  </plugin>
</plugins>

这应检查您的代码并为不在“私有”包范围内的任何内容添加导入。您应该做的另一件事是将packaging类型设置为bundle

<packaging>bundle</packaging>

但是,上面的例子是当你使用Maven作为构建工具时。如果您使用的是Gradle,则可以使用Gradle OSGi plugin来构建清单。或者,如果使用Ant,您可以使用SpringSource Bundlor project(顺便说一下,它也有一个Maven插件)。