如何在运行时在OSGI框架中动态加载Java类?

问题描述:

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

根据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容器将是无法动态加载使用ClassUtils类.forName()存在于另一个包中。我认为这是一个协作问题,其中当前bundle有一个不同的类加载器,而不是相关bundle的类加载器。

有人从这个社区遇到同样的异常?如果是,那么你采取了哪些步骤来解决运行时类的依赖问题?请分享您的想法/指针以解决上述问题。快速反应将受到高度赞赏,并可帮助我们使POC取得成功。

由于提前, Mridul普拉

+0

您是否明确将'org.springframework.ws.transport.http'添加到清单中? – artbristol 2012-03-15 10:20:52

+0

按名称加载类应该不是问题,只要知道您不能使用字节码检查工具(bnd)来生成清单。正如artbristol所说,你需要定制清单,并导入'org.springframework.ws.transport.http'。你能显示你的清单吗? – 2012-03-16 09:33:37

类加载在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插件)。

+0

实际上使用Class.forName()在OSGi中非常不鼓励。我建议OP阅读一本关于OSGi的好书,比如OSGi。http://www.amazon.com/OSGi-Action-Creating-Modular-Applications/dp/1933988916 – lothar 2012-04-15 19:40:47