首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > JAVA > Eclipse开发 >

Eclipse起步过程(源码级剖析)

2013-02-24 
Eclipse启动过程(源码级剖析)双击eclipse安装目录下的eclipse.exe运行后,会加载同一目录下的eclipse.ini文

Eclipse启动过程(源码级剖析)
双击eclipse安装目录下的eclipse.exe运行后,会加载同一目录下的eclipse.ini文件(对应RCP项目也是一样,在RCP的安装目录下会有一个RCPName.ini文件):

-startupplugins/org.eclipse.equinox.launcher_1.2.0.v20110502.jar--launcher.libraryplugins/org.eclipse.equinox.launcher.win32.win32.x86_1.1.100.v20110502-productorg.eclipse.epp.package.rcp.product--launcher.defaultActionopenFile-showsplashorg.eclipse.platform--launcher.XXMaxPermSize256M-vmargs-Dosgi.requiredJavaVersion=1.5-Xms40m-Xmx512m


其中:
-startup 指定启动的入口为:安装目录下plugins/org.eclipse.equinox.launcher_1.2.0.v20110502.jar
会加载该jar包中的org.eclipse.equinox.launcher.Main.class类并调用其main(String)完成app的启动过程

通过一个Exception.printStackTrace()方法来看一下Eclipse的大概启动过程:



图中是打印的状态栈,从下往上就是整个Eclipse(或者说RCP程序)的加载和启动过程,一直到App的启动。
下面来通过源代码,具体说明:
从org.eclipse.equinox.launcher.Main这个类开始:

在Main这个类的main()方法中下一个断的,调试状态启动Eclipse中的RCP程序就可以跟踪这个RCP启动的过程(Eclipse的过程也是类似的,其实EclipseIDE就是一个巨型的RCP):
public static void main(String[] args) {       int result = 0;       ...       result = new Main().run(args);       ...}

然后看一下run()方法:
public int run(String[] args) {       ...       basicRun(args);       ...}
主要实现就在basicRun()方法中:

protected void basicRun(String[] args) throws Exception {//记录启动启动时间System.getProperties().put("eclipse.startTime", Long.toString(System.currentTimeMillis())); //$NON-NLS-1$commands = args;//处理Command参数,并根据Command参数设置默认属性String[] passThruArgs = processCommandLine(args);if (!debug)// debug can be specified as system property as welldebug = System.getProperty(PROP_DEBUG) != null;setupVMProperties();//将VM参数写入到System.Properties中processConfiguration();//加载配置信息getInstallLocation();//获取安装路径,这里调用一下是为了确保InstallLocation被初始化// locate boot plugin (may return -dev mode variations)URL[] bootPath = getBootPath(bootLocation);//获取启动路径列表setupJNI(bootPath);//启动JNIBridge,加载dll类库//检查JDK版本if (!checkVersion(System.getProperty("java.version"),                 System.getProperty(PROP_REQUIRED_JAVA_VERSION))) return;//检查配置信息if (!checkConfigurationLocation(configurationLocation))return;setSecurityPolicy(bootPath);//设置安全策略handleSplash(bootPath);//启动闪屏,就是Eclipse(或RCP启动时IDE打开前带有进度条的界面)beforeFwkInvocation();invokeFramework(passThruArgs, bootPath);//加载框架(前面的工作都是辅助,这个才是加载框架的核心)}


下面针对其中的几个重要方法进行说明:

processConfiguration:处理配置信息
private void processConfiguration() {URL baseConfigurationLocation = null;Properties baseConfiguration = null;//在系统的配置文件中,键值对形如://osgi.configuration.area=file:/E:/eclipse-rcp-indigo-SR2-win32/eclipse/configuration/if (System.getProperty(PROP_CONFIG_AREA) == null) {String baseLocation = System.getProperty(PROP_BASE_CONFIG_AREA);if (baseLocation != null)baseConfigurationLocation = buildURL(baseLocation, true);if (baseConfigurationLocation == null)try {//在并没指定参数的情况下,将会把Location指定到: 安装目录/configurationbaseConfigurationLocation = new URL(getInstallLocation(), CONFIG_DIR);} catch (MalformedURLException e) {// leave baseConfigurationLocation null}//加载目录下的config.ini文件,对其文件中的键值对 配置信息baseConfiguration = loadConfiguration(baseConfigurationLocation);... ...}Properties configuration = baseConfiguration;if (configuration == null || !getConfigurationLocation().equals(baseConfigurationLocation))configuration = loadConfiguration(getConfigurationLocation());//把配置信息合并到System.getProperties()中mergeProperties(System.getProperties(), configuration, null);... ...

config.ini文件内容(举例)
#This configuration file was written by: org.eclipse.equinox.internal.frameworkadmin.equinox.EquinoxFwConfigFileParser#Sun Feb 17 13:24:53 CST 2013org.eclipse.update.reconcile=falseeclipse.p2.profile=epp.package.rcposgi.instance.area.default=@user.home/workspaceosgi.framework=file\:plugins/org.eclipse.osgi_3.7.2.v20120110-1415.jarequinox.use.ds=trueeclipse.buildId=M20120208-0800osgi.bundles=reference\:file\:org.eclipse.equinox.simpleconfigurator_1.0.200.v20110815-1438.jar@1\:startorg.eclipse.equinox.simpleconfigurator.configUrl=file\:org.eclipse.equinox.simpleconfigurator/bundles.infoeclipse.product=org.eclipse.platform.ideosgi.splashPath=platform\:/base/plugins/org.eclipse.platformosgi.framework.extensions=osgi.bundles.defaultStartLevel=4eclipse.application=org.eclipse.ui.ide.workbencheclipse.p2.data.area=@config.dir/../p2/

getInstallLocation() 获取当前安装路径
private URL getInstallLocation() {if (installLocation != null)return installLocation; //从系统配置信息中获取安装路径,有的话就直接返回String installArea = System.getProperty(PROP_INSTALL_AREA);if (installArea != null) {installLocation = buildURL(installArea, true);System.getProperties().put(PROP_INSTALL_AREA, installLocation.toExternalForm());return installLocation;}      //如果没有,则通过获取main类包的路径换算出安装路径ProtectionDomain domain = Main.class.getProtectionDomain();CodeSource source = null;URL result = null;source = domain.getCodeSource();result = source.getLocation();String path = decode(result.getFile());... ...installLocation = new URL(result.getProtocol(), result.getHost(), result.getPort(), path);return installLocation;}

getBootPath() 获取启动路径列表
protected URL[] getBootPath(String base) throws IOException {URL url = null;if (base != null) {url = buildURL(base, true);} else {// search in the root locationurl = getInstallLocation();String path = new File(url.getFile(), "plugins").toString(); path = searchFor(framework, path);if (url.getProtocol().equals("file")) url = new File(path).toURL();elseurl = new URL(url.getProtocol(), url.getHost(), url.getPort(), path);}//键值对,形如:osgi.framework=file:/e:/eclipse/plugins/org.eclipse.osgi_3.7.2.v20120110-1415.jar//指定osgi jar的路径if (System.getProperty(PROP_FRAMEWORK) == null)System.getProperties().put(PROP_FRAMEWORK, url.toExternalForm());//获取启动路径列表URL[] result = getDevPath(url);return result;}

setupJNI()启动JNIBridge,加载dll类库
private void setupJNI(URL[] defaultPath) {String libPath = null;/** * 获取--launcher.library的路径, 形如: * --launcher.library         *    plugins/org.eclipse.equinox.launcher.win32.win32.x86_1.1.100.v20110502 */if (library != null) {File lib = new File(library);if (lib.isDirectory()) {libPath = searchFor("eclipse", lib.getAbsolutePath()); //$NON-NLS-1$} else if (lib.exists()) {libPath = lib.getAbsolutePath();}}if (libPath == null) {/** * 根据OS、WS、Arch等信息,加载相应的本地文件(如,dll或so)。 *///find our fragment nameString fragmentOS = getOS();String fragmentWS = getWS();String fragmentArch = getArch();libPath = getLibraryPath(getFragmentString(fragmentOS, fragmentWS, fragmentArch), defaultPath);if (libPath == null && ws == null) {// no ws was specified and we didn't find the default fragment, try an alternate wsString alternateWS = getAlternateWS(fragmentWS);libPath = getLibraryPath(getFragmentString(fragmentOS, alternateWS, fragmentArch), defaultPath);if (libPath != null) {System.getProperties().put(PROP_WS, alternateWS);}}}library = libPath;if (library != null)bridge = new JNIBridge(library);//并创建JNIBridge,这个还有待研究}

invokeFramework()启动Equinox框架
private void invokeFramework(String[] passThruArgs, URL[] bootPath) throws  Exception {//如果没有指定ClassLoader,默认将boot设置为OSGi框架的ClassLoader的父类String type = System.getProperty(PROP_FRAMEWORK_PARENT_CLASSLOADER,            System.getProperty(PROP_PARENT_CLASSLOADER, PARENT_CLASSLOADER_BOOT));ClassLoader parent = null;if (PARENT_CLASSLOADER_APP.equalsIgnoreCase(type))parent = ClassLoader.getSystemClassLoader();else if (PARENT_CLASSLOADER_EXT.equalsIgnoreCase(type)) {ClassLoader appCL = ClassLoader.getSystemClassLoader();if (appCL != null)parent = appCL.getParent();} else if (PARENT_CLASSLOADER_CURRENT.equalsIgnoreCase(type))parent = this.getClass().getClassLoader();//生成一个Equinox框架的StartupClassLoader,(关于ClassLoader分层机制,还有待研究)URLClassLoader loader = new StartupClassLoader(bootPath, parent);//通过该ClassLoader加载org.eclipse.core.runtime.adaptor.EclipseStarter类,并调用其run方法Class clazz = loader.loadClass(STARTER);Method method = clazz.getDeclaredMethod("run", new Class[] {String[].class, Runnable.class}); try {//将命令行参数及闪屏线程对象传递给run方法method.invoke(clazz, new Object[] {passThruArgs, splashHandler});} catch (InvocationTargetException e) {}}


接下来看一下EclipseStarter.run()
public static Object run(String[] args, Runnable endSplashHandler) throws Exception {if (Profile.PROFILE && Profile.STARTUP)Profile.logEnter("EclipseStarter.run()", null); //$NON-NLS-1$         ... ...try {startup(args, endSplashHandler);... ...Object obj=run(null);return obj;} catch (Throwable e) {... ...} finally {... ...}return null;}


public static BundleContext startup(String[] args, Runnable endSplashHandler) throws Exception {... ...FrameworkProperties.initializeProperties();processCommandLine(args);LocationManager.initializeLocations();loadConfigurationInfo();finalizeProperties();if (Profile.PROFILE)Profile.initProps(); // catch any Profile properties set in eclipse.properties...adaptor = createAdaptor();//建立适配器framework = new Framework(adaptor);//创建Equinox框架context = framework.getBundle(0).getBundleContext();registerFrameworkShutdownHandlers();publishSplashScreen(endSplashHandler);//consoleMgr = ConsoleManager.startConsole(framework);//控制台启动,会有信息输出framework.launch();//启动框架Bundle[] startBundles = loadBasicBundles();//loading basic bundles... ...// set the framework start level to the ultimate value.  This will actually start things// running if they are persistently active.setStartLevel(getStartLevel());//StartLevel set// they should all be active by this timeensureBundlesActive(startBundles);return context;}


先到这里,有空继续分析
/** * Runs the application for which the platform was started. The platform  * must be running.  * <p> * The given argument is passed to the application being run.  If it is <code>null</code> * then the command line arguments used in starting the platform, and not consumed * by the platform code, are passed to the application as a <code>String[]</code>. * </p> * @param argument the argument passed to the application. May be <code>null</code> * @return the result of running the application * @throws Exception if anything goes wrong */public static Object run(Object argument) throws Exception {if (Profile.PROFILE && Profile.STARTUP)Profile.logEnter("EclipseStarter.run(Object)()", null); //$NON-NLS-1$if (!running)throw new IllegalStateException(EclipseAdaptorMsg.ECLIPSE_STARTUP_NOT_RUNNING);// if we are just initializing, do not run the application just return.if (initialize)return new Integer(0);try {if (appLauncher == null) {boolean launchDefault = Boolean.valueOf(FrameworkProperties.getProperty(PROP_APPLICATION_LAUNCHDEFAULT, "true")).booleanValue(); //$NON-NLS-1$// create the ApplicationLauncher and register it as a serviceappLauncher = new EclipseAppLauncher(context, Boolean.valueOf(FrameworkProperties.getProperty(PROP_ALLOW_APPRELAUNCH)).booleanValue(), launchDefault, log);appLauncherRegistration = context.registerService(ApplicationLauncher.class.getName(), appLauncher, null);// must start the launcher AFTER service restration because this method // blocks and runs the application on the current thread.  This method // will return only after the application has stopped.return appLauncher.start(argument);}return appLauncher.reStart(argument);} catch (Exception e) {if (log != null && context != null) // context can be null if OSGi failed to launch (bug 151413)logUnresolvedBundles(context.getBundles());throw e;}}

热点排行