2013-05-28 69 views
4

我試圖將彈簧DI集成到現有的jaxws項目中。我已經在tomcat本地工作,但是當我部署到遠程容器時,它似乎沒有進行類路徑掃描。我可以在日誌中看到,在tomcat上它將我的@Components註冊爲bean,但在遠程服務器上它們根本沒有提及。在osgi容器中發生彈簧組件掃描

我所看到的是以下的堆棧跟蹤。它看起來像是我不得不使用的古怪的Web容器。這是「IBM i的集成應用程序服務器」。 http://www-03.ibm.com/systems/i/software/ias/我相信這是建立在eclipse架構上的,當你安裝一個war文件時,它會將每個app轉換成一個bundle。這很棒,但它破壞了我的類路徑掃描。 ?:(

有沒有人有一個解決方案感謝

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); 

我可以看到應用程序已經被分解到文件系統中了,我不知道是否有一種方法可以在春天重寫這個loader,而不關心協議,並且顯然還在工作?我不關心容器的osgi特性。只想要我的應用程序部署。

回退似乎是放棄了類路徑掃描,而是贊成在xml中定義bean;但是這是真正的退步。 :(

+0

您可以將每個組件註冊爲osgi服務。當注入依賴時,你需要考慮註冊的osgi服務。 – SpaceTrucker

+0

你也應該讀作[爲什麼classpath中掃描你是壞的(http://lemnik.wordpress.com/2007/09/14/why-classpath-scanning-is-bad-for-you/) – SpaceTrucker

+0

博覽會點約類路徑掃描,但我怎麼能整齊地連接我的組件?我如何去註冊組件作爲osgi服務?由於我沒有使用osgi容器進行本地測試,這變得很麻煩。我甚至不關心遠程服務器是osgi,我只是想能夠部署我的應用程序。 –

回答

6

我討厭回答我自己的問題,但它似乎是報告我做了什麼的最好方法。到目前爲止,我已經提出了答案,因爲它們有助於我做出決定。

通過閱讀答案,我瞭解了爲什麼類路徑掃描不好。儘管如此,這是目前Spring框架中相當普遍的一部分。我的解決方案是去「舊skool」,並手動定義我的豆。

不能做到這一點:

<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 /> 

註釋配置,春天還是會鋼絲你的bean在一起,這只是發現正在手動完成的bean的過程。這是妥協。

理想我寧願部署與組件掃描項目的一種手段,但是從我所知,這需要改變該項目是一個OSGi容器專門構建方式。我的答案意味着它可以在osgi和普通容器中工作,因此它不太專業。

如果有人發現一個方式來部署彈簧組件掃描戰爭文件,然後我會很樂意重新考慮接受的答案。

感謝

+0

感謝分享,這讓我終於可以使它工作!似乎三年後它*仍然*是一個問題 –

+0

有趣的是,我們剛剛從IAS 8.1升級到8.5,舊版本基於「lotus expeditor」,我從來沒有對它印象深刻,這是我的一些解決方法之一8.5似乎基於WAS,並且性能更好,啓動/停止速度更快,您可以更輕鬆地設置JVM選項,您可以選擇JRE以便不再固定在6上,我相當確信它會現在支持類路徑掃描,我需要測試它,但如果它是b在WAS上調節,然後它應該做。如果你在IBM上,那麼一定要考慮升級。 –

1

的Classpath掃描是一個可怕的想法,它會在許多運行時,不只是在OSGi的突破。OSGi服務註冊表是一個更有效的方法去耦問題。

您可以使用OSGi服務OSGi的本身之外的註冊表,看看PojoSR

至於如何註冊和使用OSGi服務...因爲你使用Spring這將是最好使用Blueprint,這是一箇舊的演變名爲Spring Dynamic Modules的項目。

+0

所以我一直被告知。不過,它是春季框架的重要組成部分。當然,有一種方法可以讓這些應用程序無需重新編寫osgi風格即可運行? –

+0

我無法真正回答你的問題,因爲很久以前我停止使用Spring;但是如果classpath掃描是唯一的方法,我會非常驚訝,因爲Spring架構師應該比這更清楚。我認爲,如果您深入瞭解文檔,您可能會找到一種API或擴展機制,使您可以控制註釋Bean的發現過程。祝你好運...如果你找到答案,一定要在這裏寫下關於這裏的信息。 –

2

爲Web應用程序使用Spring,你需要春天DM運行,因此你需要有類似以下內容:

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

還是一個完整的示例來看看彈簧OSGi的樣品在pax-網址: Sample web.xml

+0

這看起來更像我想要的。我會玩這個,看看我能否得到它的工作。不幸的是我沒有太多時間,所以希望它不太複雜。乾杯。 –

+0

立即遇到問題。嘗試添加spring-osgi-web作爲maven依賴項,但現在構建被破壞,因爲它無法解析servlet-api.osgi。該maven頁面返回404。:(http://mvnrepository.com/artifact/org.springframework.osgi/servlet-api.osgi –

+0

我不知道你想做什麼,但該示例是一個示例wab,如果你想測試它,你需要一個支持osgi的web容器,例如Pax-Web,它不是你的應用程序中添加的東西 –

0

我做了Linux的這個腳本,所以我解壓TrackServer.jar並沒有從失去春季簡約(福利局這裏春天所以不是那麼高興地操縱和添加有額外的代碼)

執行主類
# 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 
+0

這是另一個問題的答案嗎? –

+0

是的,不想手動查找,它發生在我的控制器,但錯誤是相同的,所以相反,移動位碼到文件系統,後來我把它移動到/ run/shm/tracker而不是/ var /www/.../tracker。 如果你刪除了註釋,你只需要幾行代碼,這個項目啓動它自己的tomcat。放置在這裏,因爲在低級別的錯誤是相同的,這是谷歌在尋找錯誤時給我的答案。 –

+0

您可能有類似的錯誤,但我不認爲這是同一個問題。我的問題是春季類路徑掃描與OSGi容器一起使用。我們在本地機器上使用tomcat並且classpath掃描工作沒有問題。 –

1

我試着評論你的第一篇文章,但是我不能這樣做,因爲我不幸在堆棧溢出中排名。不要誤解我的意思,我不是說我在這裏有一個解決方案,但我想在這裏分享我的新的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聲明移到了上面的中心配置類中。

+0

只是爲了讓你知道我的看法:如果是解決方法,這是一種解決方案。此外,我不知道你會如何適應這個評論。另一方面,我對Spring的認識很低,我不能多說這個解決方法本身。我可以鼓勵你繼續爲網站做貢獻嗎?乾杯。 – lrnzcig

+0

@Irnzcig,謝謝你的鼓勵。我肯定會對網站做出更多貢獻,並且我覺得有必要將我的開發人員體驗分享給更多開發人員,尤其是初級開發人員。 – imarchuang

+0

這與我的解決方案基本相同,除了您使用java @Configuration而不是xml config來註冊bean。不過這是一個很好的建議。 –