在Eclipse RCP中使用Spring
注:在發(fā)完此文后,我驚奇的發(fā)現(xiàn)在新版Eclipse中(我用的是3.2M6)已經(jīng)不需要轉(zhuǎn)換ClassLoader。估計(jì)這是RCP的一個(gè)BUG,已經(jīng)被FIX。希望各位同學(xué)共同驗(yàn)證一下,如果是這樣的話,這篇文章也就沒(méi)有什么意義了。
在RCP中使用Spring,最關(guān)鍵的一點(diǎn)在于spring配置文件的讀取,因?yàn)镽CP使用自己的ClassLoader,所以用通常的方法是無(wú)法裝載Spring的配置文件。解決的思路是:在讀取Spring配置文件時(shí)將RCP的ClassLoader暫時(shí)換一下。
在這里我根據(jù)Spring配置文件在項(xiàng)目中的存放位置,給出兩種辦法。
一、配置文件存放在源代碼根目錄下。
假設(shè)我有一個(gè)叫admin_console的項(xiàng)目,我把Spring的配置文件myspring.xml放在源代碼根據(jù)目錄src下,如下圖所示
admin_console
????? --src
?????????? --cn????? //包名
?????????????? --com
????????????????? --chengang?
????????????????????? ---......???? //源代碼類(lèi)
????????? --myspring.xml????? //Spring配置文件,位于src目錄下和cn目錄平級(jí)
??????--bin
????? --lib
????? --icons
????? --properties
那么我們?cè)赗CP程序中可以這樣來(lái)裝載myspring.xml
二、配置文件存放在項(xiàng)目根目錄的某個(gè)子目錄下
項(xiàng)目根目錄和源代碼根目錄是不同的兩個(gè)概念。如上圖的項(xiàng)目結(jié)構(gòu)中,src是源代碼根目錄,admin_console是項(xiàng)目根目錄,那么properties就是項(xiàng)目根目錄下的一個(gè)子目錄。
如果將myspring.xml放入到properties目錄中,以上的讀取代碼就沒(méi)用了,讀取方法如下:
在RCP中使用Spring,最關(guān)鍵的一點(diǎn)在于spring配置文件的讀取,因?yàn)镽CP使用自己的ClassLoader,所以用通常的方法是無(wú)法裝載Spring的配置文件。解決的思路是:在讀取Spring配置文件時(shí)將RCP的ClassLoader暫時(shí)換一下。
在這里我根據(jù)Spring配置文件在項(xiàng)目中的存放位置,給出兩種辦法。
一、配置文件存放在源代碼根目錄下。
假設(shè)我有一個(gè)叫admin_console的項(xiàng)目,我把Spring的配置文件myspring.xml放在源代碼根據(jù)目錄src下,如下圖所示
admin_console
????? --src
?????????? --cn????? //包名
?????????????? --com
????????????????? --chengang?
????????????????????? ---......???? //源代碼類(lèi)
????????? --myspring.xml????? //Spring配置文件,位于src目錄下和cn目錄平級(jí)
??????--bin
????? --lib
????? --icons
????? --properties
那么我們?cè)赗CP程序中可以這樣來(lái)裝載myspring.xml
????????ClassLoader?oldLoader?=?Thread.currentThread().getContextClassLoader();
????????try?{
????????????Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
????????????ctx?=?new?ClassPathXmlApplicationContext("/myspring.xml");
????????}?finally?{
????????????Thread.currentThread().setContextClassLoader(oldLoader);
????????}
????????try?{
????????????Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
????????????ctx?=?new?ClassPathXmlApplicationContext("/myspring.xml");
????????}?finally?{
????????????Thread.currentThread().setContextClassLoader(oldLoader);
????????}
二、配置文件存放在項(xiàng)目根目錄的某個(gè)子目錄下
項(xiàng)目根目錄和源代碼根目錄是不同的兩個(gè)概念。如上圖的項(xiàng)目結(jié)構(gòu)中,src是源代碼根目錄,admin_console是項(xiàng)目根目錄,那么properties就是項(xiàng)目根目錄下的一個(gè)子目錄。
如果將myspring.xml放入到properties目錄中,以上的讀取代碼就沒(méi)用了,讀取方法如下:
????????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);
????????}
????????try?{
????????????Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
ctx?=?new FileSystemXmlApplicationContext(ProjectUtil.toFullPath("properties/myspring.xml"));
????????}?finally?{
????????????Thread.currentThread().setContextClassLoader(oldLoader);
????????}
其中ProjectUtil.toFullPath是我自己寫(xiě)的一個(gè)方法,主要是得到myspring.xml的絕對(duì)路徑,其代碼如下:
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
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 org.eclipse.core.runtime.Path;
import org.eclipse.ui.plugin.AbstractUIPlugin;
?
import com.wxxr.management.admin.console.AdminConsolePlugin;
?
/**
?* 用于插件項(xiàng)目和非插件項(xiàng)目,提供兩者通用的方法接口
?* @author chengang 2006-3-30
?*/
public class ProjectUtil {
?* 用于插件項(xiàng)目和非插件項(xiàng)目,提供兩者通用的方法接口
?* @author chengang 2006-3-30
?*/
public class ProjectUtil {
?
??? private static AbstractUIPlugin plugin = AdminConsolePlugin.getDefault();
?
??? private ProjectUtil() {}
?
??? /**
???? * 判斷當(dāng)前的運(yùn)行狀態(tài)是否為插件方式
???? * @return true=插件方式運(yùn)行
???? */
??? private static boolean isPlugin() {
??????? return plugin != null;
??? }
???? * 判斷當(dāng)前的運(yùn)行狀態(tài)是否為插件方式
???? * @return true=插件方式運(yùn)行
???? */
??? 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);
??????????? }
??? }
??????? 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);
??????? }
??? }
??????? 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;
??????? }
??? }
??????? if (isPlugin()) {
??????????? try {
??????????????? return FileLocator.toFileURL(ProjectUtil.getURL(path)).getPath();
??????????? } catch (IOException e) {
??????????????? throw new RuntimeException(path + " toFullPath is fault", e);
??????????? }
??????? } else {
??????????? return path;
??????? }
??? }
?
}
三、總結(jié)
上面兩種方式那一種更好呢?應(yīng)該是第二種。一般來(lái)說(shuō),源代碼的編譯文件會(huì)打成一個(gè)jar包(其實(shí)不打成一個(gè)JAR包也可以的,我在很多以前就嘗試過(guò)將class文件松散的部署,如果哪個(gè)類(lèi)要修改,修改后就只部署覆蓋這個(gè)class,看起來(lái)也挺方便。不過(guò)這種方式不是最佳實(shí)踐,不推薦正式發(fā)布時(shí)使用,一不心可能引起依賴它的其他類(lèi)出現(xiàn)問(wèn)題。)。如果用第一種方式在項(xiàng)目打包后,myspring.xml會(huì)打包到j(luò)ar文件中,這樣不利于今后對(duì)myspring進(jìn)行動(dòng)態(tài)修改。如果用第二種就沒(méi)有這種缺點(diǎn)。
很多時(shí)候,在Eclipse開(kāi)發(fā)環(huán)境中,運(yùn)行RCP程序沒(méi)有問(wèn)題。但導(dǎo)出項(xiàng)目后,在獨(dú)立的環(huán)境中卻報(bào)配置文件(不光是Spring)找不到的錯(cuò)誤,解決的方法都基本與此相同。
posted on 2006-04-26 17:44 陳剛 閱讀(7523) 評(píng)論(22) 編輯 收藏 所屬分類(lèi): Eclipse