如何在运行时在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普拉
类加载在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插件)。
实际上使用Class.forName()在OSGi中非常不鼓励。我建议OP阅读一本关于OSGi的好书,比如OSGi。http://www.amazon.com/OSGi-Action-Creating-Modular-Applications/dp/1933988916 – lothar 2012-04-15 19:40:47
您是否明确将'org.springframework.ws.transport.http'添加到清单中? – artbristol 2012-03-15 10:20:52
按名称加载类应该不是问题,只要知道您不能使用字节码检查工具(bnd)来生成清单。正如artbristol所说,你需要定制清单,并导入'org.springframework.ws.transport.http'。你能显示你的清单吗? – 2012-03-16 09:33:37