6

我正在尝试将 spring DI 集成到现有的 jaxws 项目中。我已经在 tomcat 上本地工作了,但是当我部署到远程容器时,它似乎没有进行类路径扫描。我可以在 tomcat 上将我的 @Components 注册为 bean 的日志中看到,但在远程服务器上根本没有提到它们。

我看到的是下面的堆栈跟踪。看起来这取决于我必须使用的古怪 Web 容器。它是“IBM i 的集成应用服务器”。http://www-03.ibm.com/systems/i/software/ias/我相信这是建立在 eclipse 架构上的,当您安装一个 war 文件时,它会将每个应用程序转换为一个包。这很好,但它打破了我的类路径扫描。:(

有人对此有解决方案吗?谢谢

673 [Thread-6] WARN  org.springframework.core.io.support.PathMatchingResourcePatternResolver  - Cannot search for matching files underneath URL [bundleresource://32/com/company/application/] because it does not correspond to a directory in the file system
java.io.FileNotFoundException: URL [bundleresource://32/com/company/application/] cannot be resolved to absolute file path because it does not reside in the file system: bundleresource://32/com/company/application/
    at org.springframework.util.ResourceUtils.getFile(ResourceUtils.java:205)
    at org.springframework.core.io.AbstractFileResolvingResource.getFile(AbstractFileResolvingResource.java:52)
    at org.springframework.core.io.UrlResource.getFile(UrlResource.java:169)
    at org.springframework.core.io.support.PathMatchingResourcePatternResolver.doFindPathMatchingFileResources(PathMatchingResourcePatternResolver.java:526)
    at org.springframework.web.context.support.ServletContextResourcePatternResolver.doFindPathMatchingFileResources(ServletContextResourcePatternResolver.java:92)
    at org.springframework.core.io.support.PathMatchingResourcePatternResolver.findPathMatchingResources(PathMatchingResourcePatternResolver.java:347)
    at org.springframework.core.io.support.PathMatchingResourcePatternResolver.getResources(PathMatchingResourcePatternResolver.java:266)
    at org.springframework.context.support.AbstractApplicationContext.getResources(AbstractApplicationContext.java:1269)
    at org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider.findCandidateComponents(ClassPathScanningCandidateComponentProvider.java:248)
    at org.springframework.context.annotation.ClassPathBeanDefinitionScanner.doScan(ClassPathBeanDefinitionScanner.java:242)
    at org.springframework.context.annotation.ComponentScanBeanDefinitionParser.parse(ComponentScanBeanDefinitionParser.java:84)
    at org.springframework.beans.factory.xml.NamespaceHandlerSupport.parse(NamespaceHandlerSupport.java:73)
    at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(BeanDefinitionParserDelegate.java:1438)
    at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(BeanDefinitionParserDelegate.java:1428)
    at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.parseBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:185)
    at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.doRegisterBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:139)
    at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.registerBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:108)
    at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.registerBeanDefinitions(XmlBeanDefinitionReader.java:493)
    at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:390)
    at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:334)
    at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:302)
    at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:174)
    at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:209)
    at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:180)
    at org.springframework.web.context.support.XmlWebApplicationContext.loadBeanDefinitions(XmlWebApplicationContext.java:125)
    at org.springframework.web.context.support.XmlWebApplicationContext.loadBeanDefinitions(XmlWebApplicationContext.java:94)
    at org.springframework.context.support.AbstractRefreshableApplicationContext.refreshBeanFactory(AbstractRefreshableApplicationContext.java:130)
    at org.springframework.context.support.AbstractApplicationContext.obtainFreshBeanFactory(AbstractApplicationContext.java:537)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:451)
    at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:389)
    at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:294)
    at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:112)
    at com.ibm.ws.webcontainer.webapp.WebApp.notifyServletContextCreated(WebApp.java:1678)
    at com.ibm.ws.webcontainer.webapp.WebApp.commonInitializationFinish(WebApp.java:371)
    at com.ibm.ws.webcontainer.webapp.WebApp.initialize(WebApp.java:347)
    at com.ibm.ws.webcontainer.webapp.WebGroup.addWebApplication(WebGroup.java:134)
    at com.ibm.ws.webcontainer.VirtualHost.addWebApplication(VirtualHost.java:145)
    at com.ibm.ws.webcontainer.WebContainer.addWebApp(WebContainer.java:542)
    at com.ibm.ws.webcontainer.WebContainer.addWebApplication(WebContainer.java:513)
    at com.ibm.pvc.internal.webcontainer.trackers.WebApplicationServiceTracker.addingService(WebApplicationServiceTracker.java:94)
    at org.osgi.util.tracker.ServiceTracker$Tracked.trackAdding(ServiceTracker.java:1064)
    at org.osgi.util.tracker.ServiceTracker$Tracked.trackInitialServices(ServiceTracker.java:926)
    at org.osgi.util.tracker.ServiceTracker.open(ServiceTracker.java:330)
    at org.osgi.util.tracker.ServiceTracker.open(ServiceTracker.java:274)
    at com.ibm.pvc.internal.webcontainer.trackers.XMLParserServiceTracker.initializeTrackers(XMLParserServiceTracker.java:520)
    at com.ibm.pvc.internal.webcontainer.trackers.XMLParserServiceTracker.startWebcontainer(XMLParserServiceTracker.java:235)
    at com.ibm.pvc.internal.webcontainer.trackers.XMLParserServiceTracker.addingService(XMLParserServiceTracker.java:140)
    at org.osgi.util.tracker.ServiceTracker$Tracked.trackAdding(ServiceTracker.java:1064)
    at org.osgi.util.tracker.ServiceTracker$Tracked.trackInitialServices(ServiceTracker.java:926)
    at org.osgi.util.tracker.ServiceTracker.open(ServiceTracker.java:330)
    at org.osgi.util.tracker.ServiceTracker.open(ServiceTracker.java:274)
    at com.ibm.pvc.internal.webcontainer.WebContainerActivator.start(WebContainerActivator.java:45)
    at org.eclipse.osgi.framework.internal.core.BundleContextImpl$2.run(BundleContextImpl.java:1009)
    at java.security.AccessController.doPrivileged(AccessController.java:251)
    at org.eclipse.osgi.framework.internal.core.BundleContextImpl.startActivator(BundleContextImpl.java:1003)
    at org.eclipse.osgi.framework.internal.core.BundleContextImpl.start(BundleContextImpl.java:984)
    at org.eclipse.osgi.framework.internal.core.BundleHost.startWorker(BundleHost.java:350)
    at org.eclipse.osgi.framework.internal.core.AbstractBundle.start(AbstractBundle.java:279)
    at com.ibm.rcp.internal.util.BundleManager.start(BundleManager.java:74)
    at com.ibm.rcp.internal.util.BundleManager.start(BundleManager.java:179)
    at com.ibm.rcp.lifecycle.internal.application.BundleControlImpl.start(BundleControlImpl.java:125)
    at com.ibm.rcp.lifecycle.internal.application.BundleControlImpl.start(BundleControlImpl.java:106)
    at com.ibm.rcp.lifecycle.application.BundleControl.start(BundleControl.java:89)
    at com.ibm.lwi.application.LWIApplication.run(LWIApplication.java:149)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:48)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:600)
    at org.eclipse.equinox.internal.app.EclipseAppContainer.callMethodWithException(EclipseAppContainer.java:574)
    at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:195)
    at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:110)
    at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:79)
    at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:386)
    at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:179)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:48)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:600)
    at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:561)
    at org.eclipse.equinox.launcher.Main.basicRun(Main.java:501)
    at org.eclipse.equinox.launcher.Main.run(Main.java:1239)
    at org.eclipse.equinox.launcher.Main.main(Main.java:1215)
    at org.eclipse.core.launcher.Main.main(Main.java:30)
    at com.ibm.lwi.LaunchLWI$1.run(LaunchLWI.java:731)  

查看引发异常的代码,它正在检查协议是否为 file://。

if (!URL_PROTOCOL_FILE.equals(resourceUrl.getProtocol())) {
            throw new FileNotFoundException(
                    description + " cannot be resolved to absolute file path " +
                    "because it does not reside in the file system: " + resourceUrl);

我可以看到该应用程序已被分解到文件系统中。我想知道是否有办法在春天覆盖这个加载器而不关心协议并且显然仍然有效?我不关心容器的 osgi 特性。我只想部署我的应用程序。

回退似乎是放弃类路径扫描,转而在 xml 中定义 bean,但那是真正的退一步 imo。:(

4

5 回答 5

8

我讨厌回答我自己的问题的想法,但这似乎是报告我所做的事情的最佳方式。到目前为止,我已经对答案投了赞成票,因为它们有助于我做出决定。

通过阅读答案,我了解了为什么类路径扫描不好。尽管如此,它现在是 Spring 框架中相当常见的部分。我的解决方案是去“old skool”并手动定义我的bean。

不能这样做:

<context:component-scan base-package="com.company.application.services" />

改为这样做:

<bean id="service1" class="com.company.application.services.impl.Service1" />
<bean id="service2" class="com.company.application.services.impl.Service2" />

你至少仍然可以这样做:

<context:annotation-config />

注释配置意味着 spring 仍然会将您的 bean 连接在一起,这只是发现正在手动完成的 bean 的过程。这就是妥协。

理想情况下,我更喜欢通过组件扫描来部署项目的方法,但据我所知,这需要改变项目专门为 osgi 容器构建的方式。我的回答意味着它可以在 osgi 和普通容器中工作,因此它不那么专业。

如果有人找到一种方法来部署带有弹簧组件扫描的战争文件,那么我很乐意重新考虑接受的答案。

谢谢

于 2013-05-30T10:54:19.557 回答
2

为了让您的 web 应用程序使用 spring 运行,您需要 spring dm,因此您需要具有以下内容:

    <context-param>
    <param-name>contextClass</param-name>
    <param-value>org.springframework.osgi.web.context.support.OsgiBundleXmlWebApplicationContext</param-value>
</context-param>

或者要查看完整示例,请查看 pax-web 上的 spring-osgi 示例: 示例 web.xml

于 2013-05-29T06:49:05.780 回答
2

我尝试评论您的初始帖子,但不幸的是,由于我在 stackoverflow 中的排名,我无法这样做。不要误会我的意思,我并不是说我在这里有解决方案,但我想在这里分享我在较新版本的 Spring 框架中的解决方法。

首先,我有一个很大的配置类,它作为该AnnotationConfigApplicationContext(PseudoSpringBootApplication.class)语句中的条目提供服务。

/**
 * This class serves as the entry point from OSGI framework to Spring framework
 *
 */
@Configuration
//@ComponentScan
//@SpringBootApplication
public class PseudoSpringBootApplication {

  @Autowired
  ApplicationContext context;

  @Bean
  DummySpringBean1 dummySpringBean1() {
    return new DummySpringBean("This is a dummy message");
  }

  @Bean
  DummySpringBean2 dummySpringBean2() {
    return new DummySpringBean("This is a dummy message");
  }

}

基本上,由于 @ComponentScan 不适用于 OSGI 插件,(正如您在回答帖子中提到的,这主要是因为 Spring 框架尝试扫描类假设工件在文件系统中,但是,在这种情况下,OSGI (例如,Apache Felix)已将 FILE:// 前缀 url 转换为其内部 bundle:// 前缀。 java.io.FileNotFoundException: URL [bundle://21.0:1/com/***] cannot be resolved to absolute file path because it does not reside in the file system: bundle://21.0:1/com/*** 尽管如此,@Autowired 仍在工作。我已经展示了下面的示例代码,其中 DummySpringBean2 具有 DummySpringBean1 的依赖项并且是@Autowired 注释。

//@Component
class DummySpringBean1 {

  private final String dummyMessage;

  DummySpringBean1(String dummyMessage) {
    this.dummyMessage = dummyMessage;
  }
}

对于 DummySpringBean2,它依赖于 DummySpringBean1。

//@Component
class DummySpringBean2 {

  private final String dummyMessage;

  @Autowired
  private DummySpringBean1 bean1;

  DummySpringBean(String dummyMessage) {
    this.dummyMessage = dummyMessage;
  }
}

所以我把所有的bean声明都移到了上面的中央配置类中。

于 2017-03-10T15:29:18.753 回答
1

类路径扫描是一个糟糕的想法,它会在许多运行时中断,而不仅仅是在 OSGi 中。OSGi 服务注册中心是解决解耦问题的一种更有效的方法。

您可以在 OSGi 本身之外使用 OSGi 服务注册表,看看PojoSR

至于如何注册和使用 OSGi 服务......因为您使用的是 Spring,所以最好使用Blueprint,这是一个名为 Spring Dynamic Modules 的旧项目的演变。

于 2013-05-28T17:11:25.100 回答
0

我为 linux 做了这个小脚本,所以我解压缩了 TrackServer.jar 并执行主类,而不会失去 Spring 的简单性(这里是新手,所以不太高兴在那里操作并添加额外的代码)

# Remove any old file before new version
rm -rf tracker;
# Recreate executable folder
mkdir tracker;
# copy main jar to executable folder
cp TrackServer.jar tracker;
# move to executable folder
cd tracker;
# Extract jar on executable folder
jar xf TrackServer.jar;
# Execute main class (at the end of the line) 
# with all the jar dependencies that came 
# in original TrackerServer.jar
java -cp '.;'`ls -dm *.jar | sed -e ':a' -e 'N' -e '$!ba' -e 's/\n/ /g' | sed -e 's/,[ \n\r\t]/:/g'` incodemode.mainApp.Main;
# sed bits are for getting .:dependency1.jar:dependency2.jar etc...
# incodemode.mainApp.Main is the full class path of the Main class
于 2016-03-01T04:59:33.013 回答