子在川上曰

            逝者如斯夫不舍晝夜
          隨筆 - 71, 文章 - 0, 評論 - 915, 引用 - 0
          數據加載中……

          在Eclipse RCP中使用Spring

          注:在發完此文后,我驚奇的發現在新版Eclipse中(我用的是3.2M6)已經不需要轉換ClassLoader。估計這是RCP的一個BUG,已經被FIX。希望各位同學共同驗證一下,如果是這樣的話,這篇文章也就沒有什么意義了。


          在RCP中使用Spring,最關鍵的一點在于spring配置文件的讀取,因為RCP使用自己的ClassLoader,所以用通常的方法是無法裝載Spring的配置文件。解決的思路是:在讀取Spring配置文件時將RCP的ClassLoader暫時換一下。

          在這里我根據Spring配置文件在項目中的存放位置,給出兩種辦法。

          一、配置文件存放在源代碼根目錄下。

          假設我有一個叫admin_console的項目,我把Spring的配置文件myspring.xml放在源代碼根據目錄src下,如下圖所示
          admin_console
          ????? --src
          ?????????? --cn????? //包名
          ?????????????? --com
          ????????????????? --chengang?
          ????????????????????? ---......???? //源代碼類
          ????????? --myspring.xml????? //Spring配置文件,位于src目錄下和cn目錄平級
          ??????--bin
          ????? --lib
          ????? --icons
          ????? --properties


          那么我們在RCP程序中可以這樣來裝載myspring.xml
          ????????ClassLoader?oldLoader?=?Thread.currentThread().getContextClassLoader();
          ????????
          try?{
          ????????????Thread.currentThread().setContextClassLoader(this.getClass()
          .getClassLoader());
          ????????????
          ctx?=?new?ClassPathXmlApplicationContext("/myspring.xml");
          ????????}?finally?{
          ????????????Thread.currentThread().setContextClassLoader(oldLoader);
          ????????}



          二、配置文件存放在項目根目錄的某個子目錄下

          項目根目錄和源代碼根目錄是不同的兩個概念。如上圖的項目結構中,src是源代碼根目錄,admin_console是項目根目錄,那么properties就是項目根目錄下的一個子目錄。

          如果將myspring.xml放入到properties目錄中,以上的讀取代碼就沒用了,讀取方法如下:

          ????????ClassLoader?oldLoader?=?Thread.currentThread().getContextClassLoader();
          ????????
          try?{
          ????????????Thread.currentThread().setContextClassLoader(this.getClass()
          .getClassLoader());
             ctx?=?new FileSystemXmlApplicationContext(ProjectUtil.toFullPath("properties/myspring.xml"));
          ????????}?finally?{
          ????????????Thread.currentThread().setContextClassLoader(oldLoader);
          ????????}

          其中ProjectUtil.toFullPath是我自己寫的一個方法,主要是得到myspring.xml的絕對路徑,其代碼如下:

          import java.io.IOException;
          import java.io.InputStream;
          import java.net.MalformedURLException;
          import java.net.URL;
          ?
          import org.eclipse.core.runtime.FileLocator;
          import org.eclipse.core.runtime.Path;
          import org.eclipse.ui.plugin.AbstractUIPlugin;
          ?
          import com.wxxr.management.admin.console.AdminConsolePlugin;
          ?
          /**
          ?* 用于插件項目和非插件項目,提供兩者通用的方法接口
          ?* @author chengang 2006-3-30
          ?*/
          public class ProjectUtil {
          ?
          ??? private static AbstractUIPlugin plugin = AdminConsolePlugin.getDefault();
          ?
          ??? private ProjectUtil() {}
          ?
          ??? /**
          ???? * 判斷當前的運行狀態是否為插件方式
          ???? * @return true=插件方式運行
          ???? */
          ??? private static boolean isPlugin() {
          ??????? return plugin != null;
          ??? }
          ?
          ??? public static URL getURL(String path) {
          ??????? if (isPlugin())//如果是插件
          ??????????? return FileLocator.find(plugin.getBundle(), new Path(path), null);
          ??????? else
          ??????????? try {
          ??????????????? return new URL("file:" + path);
          ??????????? } catch (MalformedURLException e) {
          ??????????????? throw new RuntimeException(path + " is error", e);
          ??????????? }
          ??? }
          ?
          ??? public static InputStream getInputStream(String path) {
          ??????? URL url = getURL(path);
          ??????? try {
          ??????????? return url.openStream();
          ??????? } catch (IOException e) {
          ??????????? throw new RuntimeException(e);
          ??????? }
          ??? }
          ?
          ??? public static String toFullPath(String path) {
          ??????? if (isPlugin()) {
          ??????????? try {
          ??????????????? return FileLocator.toFileURL(ProjectUtil.getURL(path)).getPath();
          ??????????? } catch (IOException e) {
          ??????????????? throw new RuntimeException(path + " toFullPath is fault", e);
          ??????????? }
          ??????? } else {
          ??????????? return path;
          ??????? }
          ??? }
          ?
          }


          三、總結

          上面兩種方式那一種更好呢?應該是第二種。一般來說,源代碼的編譯文件會打成一個jar包(其實不打成一個JAR包也可以的,我在很多以前就嘗試過將class文件松散的部署,如果哪個類要修改,修改后就只部署覆蓋這個class,看起來也挺方便。不過這種方式不是最佳實踐,不推薦正式發布時使用,一不心可能引起依賴它的其他類出現問題。)。如果用第一種方式在項目打包后,myspring.xml會打包到jar文件中,這樣不利于今后對myspring進行動態修改。如果用第二種就沒有這種缺點。

          很多時候,在Eclipse開發環境中,運行RCP程序沒有問題。但導出項目后,在獨立的環境中卻報配置文件(不光是Spring)找不到的錯誤,解決的方法都基本與此相同。

          posted on 2006-04-26 17:44 陳剛 閱讀(7522) 評論(22)  編輯  收藏 所屬分類: Eclipse

          評論

          # re: 在Eclipse RCP中使用Spring  回復  更多評論   

          ClassLoader oldLoader = Thread.currentThread().getContextClassLoader();
          try {
          Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
          ctx = new ClassPathXmlApplicationContext("/myspring.xml");
          } finally {
          Thread.currentThread().setContextClassLoader(oldLoader);
          }
          1,這端代碼放到RCP的Application中可以嗎?
          2,ClassPathXmlApplicationContext在RCP開發中沒有這個類,如果按同樣的方法來配置Hibernate應該使用那個類呢?
          3,恕我愚笨能給詳細教教小弟配置一下嗎?
          2006-08-23 21:42 | qiuliang

          # re: 在Eclipse RCP中使用Spring  回復  更多評論   

          其實我得,目的就是在RCP中配置Hibernate!spring我并不懂,陳先生,如果我問的不對還請你見涼,但是我真的很渴望知道怎么在RCP中配置和使用Hibernate!
          2006-08-23 21:45 | qiuliang

          # re: 在Eclipse RCP中使用Spring  回復  更多評論   

          @qiuliang
          關于hibernate看這篇文章
          http://www.aygfsteel.com/chengang/archive/2006/08/24/65484.html
          2006-08-24 12:29 | 陳剛

          # re: 在Eclipse RCP中使用Spring  回復  更多評論   

          這個問題貌似并沒有在ECLIPSE3.2中被完美解決。事實上也不是一個需要被解決的BUG。我曾經碰到過相同的問題,特地下載了ECLIPSE3.2試驗,但是并沒有成功。
          談談這個問題的根源:ECLIPSE的每個PLUGIN被自己專屬的CLASSLOADER所加載,專屬的CLASSLOADER也只能識別出當前PLUGIN下的類和配置文件,所以如果在當前PLUGIN下調用有依賴關系的另一個PLUGIN中的CLASS來動態加載當前PLUGIN下的類或者配置文件,那么錯誤就發生了,因為另一個PLUGIN的CLASSLOADER找不到它需要的類或者配置文件。
          ECLIPSE 3.1起對這個問題有一個優雅的解決方式,就是在上述的兩個PLUGIN的MANIFEST文件中配置注冊關系。

          陳師傅可以驗證一下我的說法。有空我可以貼出例證代碼。
          2006-09-26 11:42 | JIAWEI

          # re: 在Eclipse RCP中使用Spring  回復  更多評論   

          @JIAWEI
          是的新版Eclipse已經解決這個問題。
          2006-10-08 09:57 | 陳剛

          # re: 在Eclipse RCP中使用Spring  回復  更多評論   

          沒仔細研究過RCP的ClassLoader,不太理解陳師傅所說。

          我在插件開發中是使用spring的方法類似陳師傅說的第二種:放在properties文件夾下。不過我沒有用ProjectUtils這樣的方法找絕對路徑,我的方法是:
          1、將properties文件夾加入到項目的Runtime ClassPath中
          2、在getApplicatonContext時用ClassPathXmlApplicationContext就能去properties文件夾中去找;

          BTW:
          RCP的ClassLoader是不是就是在啟動時自動裝載所需類?
          2007-03-24 10:45 | 烏黑的大白馬

          # re: 在Eclipse RCP中使用Spring  回復  更多評論   

          陳老師,請問下我用您的第二種方式的的話,那打包成Jar文件中會不會有什么錯誤,打包后應該只有一個bin目錄,沒有那個src和config(配置文件放這里),可以得到文件路徑嗎?
          2007-08-08 11:33 | liuraoxing

          # re: 在Eclipse RCP中使用Spring  回復  更多評論   

          打包后不會有 bin目錄的,所以你打包的目錄結構錯了。
          具體請參考<Eclipse從入門到精通>第二版的,第32章'RCP項目的打包和發行',重點看圖32.13的下圖
          2007-08-10 08:37 | 陳剛

          # re: 在Eclipse RCP中使用Spring  回復  更多評論   

          @烏黑的大白馬
          請看文章前面的紅色文字,這篇文章實際已經沒有意義。
          2007-08-10 08:39 | 陳剛

          # re: 在Eclipse RCP中使用Spring  回復  更多評論   

          為什么,我是安裝陳老師說的那樣,但是為什么還報這樣的錯誤,能給予說明下嗎?
          !ENTRY org.eclipse.osgi 4 0 2007-09-21 09:14:12.015
          !MESSAGE Application error
          !STACK 1
          org.eclipse.core.runtime.CoreException: Plug-in TestPlug was unable to load class testplug.Application.
          at org.eclipse.core.internal.registry.osgi.RegistryStrategyOSGI.throwException(RegistryStrategyOSGI.java:165)
          at org.eclipse.core.internal.registry.osgi.RegistryStrategyOSGI.createExecutableExtension(RegistryStrategyOSGI.java:149)
          at org.eclipse.core.internal.registry.ExtensionRegistry.createExecutableExtension(ExtensionRegistry.java:759)
          at org.eclipse.core.internal.registry.ConfigurationElement.createExecutableExtension(ConfigurationElement.java:243)
          at org.eclipse.core.internal.registry.ConfigurationElementHandle.createExecutableExtension(ConfigurationElementHandle.java:51)
          at org.eclipse.core.internal.runtime.PlatformActivator$1.run(PlatformActivator.java:74)
          at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:92)
          at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:68)
          at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:400)
          at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:177)
          at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
          at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
          at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
          at java.lang.reflect.Method.invoke(Method.java:585)
          at org.eclipse.core.launcher.Main.invokeFramework(Main.java:336)
          at org.eclipse.core.launcher.Main.basicRun(Main.java:280)
          at org.eclipse.core.launcher.Main.run(Main.java:977)
          at org.eclipse.core.launcher.Main.main(Main.java:952)
          org.eclipse.core.runtime.CoreException[1]: java.lang.ClassNotFoundException: testplug.Application
          at org.eclipse.osgi.framework.internal.core.BundleLoader.findClass(BundleLoader.java:402)
          at org.eclipse.osgi.framework.internal.core.BundleLoader.findClass(BundleLoader.java:347)
          at org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader.loadClass(DefaultClassLoader.java:83)
          at java.lang.ClassLoader.loadClass(ClassLoader.java:251)
          at org.eclipse.osgi.framework.internal.core.BundleLoader.loadClass(BundleLoader.java:278)
          at org.eclipse.osgi.framework.internal.core.BundleHost.loadClass(BundleHost.java:227)
          at org.eclipse.osgi.framework.internal.core.AbstractBundle.loadClass(AbstractBundle.java:1245)
          at org.eclipse.core.internal.registry.osgi.RegistryStrategyOSGI.createExecutableExtension(RegistryStrategyOSGI.java:147)
          at org.eclipse.core.internal.registry.ExtensionRegistry.createExecutableExtension(ExtensionRegistry.java:759)
          at org.eclipse.core.internal.registry.ConfigurationElement.createExecutableExtension(ConfigurationElement.java:243)
          at org.eclipse.core.internal.registry.ConfigurationElementHandle.createExecutableExtension(ConfigurationElementHandle.java:51)
          at org.eclipse.core.internal.runtime.PlatformActivator$1.run(PlatformActivator.java:74)
          at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:92)
          at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:68)
          at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:400)
          at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:177)
          at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
          at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
          at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
          at java.lang.reflect.Method.invoke(Method.java:585)
          at org.eclipse.core.launcher.Main.invokeFramework(Main.java:336)
          at org.eclipse.core.launcher.Main.basicRun(Main.java:280)
          at org.eclipse.core.launcher.Main.run(Main.java:977)
          at org.eclipse.core.launcher.Main.main(Main.java:952)
          2007-09-21 09:15 | cj_829cai

          # re: 在Eclipse RCP中使用Spring  回復  更多評論   

          @cj_829cai
          unable to load class testplug.Application
          這一句報錯是關鍵。說明你的項目配置有問題,導致找不到Application類。
          2007-09-24 08:46 | 陳剛

          # re: 在Eclipse RCP中使用Spring  回復  更多評論   

          陳老師,有沒有簡單一點的例題?
          如果有時間話能發一下嗎?
          為了這個問題.我還專門買了你的書第二版里可惜沒有講到.
          caijin_001@163.com
          2007-09-24 10:03 | cj_829cai

          # re: 在Eclipse RCP中使用Spring  回復  更多評論   

          這次是找不到spring文件.一開始我以為是導包的問題,我確定包是沒有問題的.我用一個測試類已經能正常使用spring.但是把這個正確的代碼拷貝過來就出問題了
          .我是按照你說的把類加載器轉換了一下.還是出現這樣的錯誤.急啊
          !ENTRY org.eclipse.ui.workbench 4 0 2007-09-24 09:55:44.635
          !MESSAGE Unable to create view ID MyCRP.view2: org/springframework/beans/factory/BeanFactory
          !STACK 0
          java.lang.NoClassDefFoundError: org/springframework/beans/factory/BeanFactory
          at com.view.TestView.seleteD(TestView.java:71)
          at com.view.TestView.createPartControl(TestView.java:55)
          at org.eclipse.ui.internal.ViewReference.createPartHelper(ViewReference.java:332)
          at org.eclipse.ui.internal.ViewReference.createPart(ViewReference.java:197)
          at org.eclipse.ui.internal.WorkbenchPartReference.getPart(WorkbenchPartReference.java:566)
          at org.eclipse.ui.internal.PartPane.setVisible(PartPane.java:290)
          at org.eclipse.ui.internal.ViewPane.setVisible(ViewPane.java:525)
          at org.eclipse.ui.internal.presentations.PresentablePart.setVisible(PresentablePart.java:140)
          at org.eclipse.ui.internal.presentations.util.PresentablePartFolder.select(PresentablePartFolder.java:268)
          at org.eclipse.ui.internal.presentations.util.LeftToRightTabOrder.select(LeftToRightTabOrder.java:65)
          at org.eclipse.ui.internal.presentations.util.TabbedStackPresentation.selectPart(TabbedStackPresentation.java:394)
          at org.eclipse.ui.internal.PartStack.refreshPresentationSelection(PartStack.java:1144)
          at org.eclipse.ui.internal.PartStack.setSelection(PartStack.java:1097)
          at org.eclipse.ui.internal.PartStack.showPart(PartStack.java:1311)
          at org.eclipse.ui.internal.PartStack.createControl(PartStack.java:601)
          at org.eclipse.ui.internal.PartStack.createControl(PartStack.java:532)
          at org.eclipse.ui.internal.PartSashContainer.createControl(PartSashContainer.java:562)
          at org.eclipse.ui.internal.PerspectiveHelper.activate(PerspectiveHelper.java:244)
          at org.eclipse.ui.internal.Perspective.onActivate(Perspective.java:815)
          at org.eclipse.ui.internal.WorkbenchPage.onActivate(WorkbenchPage.java:2436)
          at org.eclipse.ui.internal.WorkbenchWindow$6.run(WorkbenchWindow.java:2616)
          at org.eclipse.swt.custom.BusyIndicator.showWhile(BusyIndicator.java:67)
          at org.eclipse.ui.internal.WorkbenchWindow.setActivePage(WorkbenchWindow.java:2597)
          at org.eclipse.ui.internal.WorkbenchWindow.busyOpenPage(WorkbenchWindow.java:658)
          at org.eclipse.ui.internal.Workbench.busyOpenWorkbenchWindow(Workbench.java:795)
          at org.eclipse.ui.internal.Workbench.doOpenFirstTimeWindow(Workbench.java:1437)
          at org.eclipse.ui.internal.Workbench.openFirstTimeWindow(Workbench.java:1388)
          at org.eclipse.ui.internal.WorkbenchConfigurer.openFirstTimeWindow(WorkbenchConfigurer.java:190)
          at org.eclipse.ui.application.WorkbenchAdvisor.openWindows(WorkbenchAdvisor.java:708)
          at org.eclipse.ui.internal.Workbench.init(Workbench.java:1085)
          at org.eclipse.ui.internal.Workbench.runUI(Workbench.java:1847)
          at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.java:419)
          at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:149)
          at mycrp.Application.run(Application.java:18)
          at org.eclipse.core.internal.runtime.PlatformActivator$1.run(PlatformActivator.java:78)
          at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:92)
          at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:68)
          at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:400)
          at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:177)
          at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
          at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
          at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
          at java.lang.reflect.Method.invoke(Method.java:585)
          at org.eclipse.core.launcher.Main.invokeFramework(Main.java:336)
          at org.eclipse.core.launcher.Main.basicRun(Main.java:280)
          at org.eclipse.core.launcher.Main.run(Main.java:977)
          at org.eclipse.core.launcher.Main.main(Main.java:952)
          2007-09-24 10:20 | cj_829cai

          # re: 在Eclipse RCP中使用Spring  回復  更多評論   

          謝謝陳老師.我在你的Hibernate中找到的答案,謝謝了
          2007-09-25 11:29 | cj_829cai

          # re: 在Eclipse RCP中使用Spring  回復  更多評論   

          @cj_829cai
          舉一推三,聰明
          2007-09-26 01:12 | 陳剛

          # re: 在Eclipse RCP中使用Spring  回復  更多評論   

          陳老是,還有一個問題。不知道RCP里面能不能使用SWT的shell窗體?
          2007-09-29 18:07 | cj_829cai

          # re: 在Eclipse RCP中使用Spring  回復  更多評論   

          @cj_829cai
          你試過了嗎
          2007-09-29 20:54 | 陳剛

          # re: 在Eclipse RCP中使用Spring  回復  更多評論   

          我試過了。是可以用的。但是有一個問題。就是shell窗口是沒有辦法,彈出需要在任務欄里點擊才能現實出窗體。不知道這是什么原因?
          2007-10-09 15:09 | cj_829cai

          # re: 在Eclipse RCP中使用Spring  回復  更多評論   

          @cj_829cai
          那是shell的參數沒有設置好。參考一樣本書SWT內容中關于shell的介紹。
          2007-10-10 08:49 | 陳剛

          # re: 在Eclipse RCP中使用Spring  回復  更多評論   

          陳老師。能否把TitleAreaDialog變成非模式的窗口?
          2007-10-16 18:29 | cj_829cai

          # re: 在Eclipse RCP中使用Spring  回復  更多評論   

          com.wxxr.management.admin.console.AdminConsolePlugin;
          請教這一個包名是什么? 我沒找到相應的jar文件。
          2008-06-18 19:04 | win

          # re: 在Eclipse RCP中使用Spring解析問題  回復  更多評論   

          你好,我用你的方法,文件找到了。可是解析出現了不少問題,求指導
          2014-05-20 09:15 | 王傳
          主站蜘蛛池模板: 临桂县| 台前县| 黑龙江省| 成武县| 长岛县| 福海县| 化隆| 恩平市| 留坝县| 丘北县| 临沂市| 龙陵县| 原平市| 会昌县| 若尔盖县| 宁阳县| 水城县| 商洛市| 麻栗坡县| 洛扎县| 隆德县| 南宁市| 宁津县| 方正县| 乌兰察布市| 宜章县| 明光市| 徐水县| 阿荣旗| 玛曲县| 无棣县| 喀喇沁旗| 和田市| 宁陵县| 黔东| 阳谷县| 江城| 额济纳旗| 新宁县| 麟游县| 唐山市|