`

Eclipse启动过程(源码级剖析)

 
阅读更多
双击eclipse安装目录下的eclipse.exe运行后,会加载同一目录下的eclipse.ini文件(对应RCP项目也是一样,在RCP的安装目录下会有一个RCPName.ini文件):
-startup
plugins/org.eclipse.equinox.launcher_1.2.0.v20110502.jar

--launcher.library
plugins/org.eclipse.equinox.launcher.win32.win32.x86_1.1.100.v20110502
-product
org.eclipse.epp.package.rcp.product
--launcher.defaultAction
openFile
-showsplash
org.eclipse.platform
--launcher.XXMaxPermSize
256M
-vmargs
-Dosgi.requiredJavaVersion=1.5
-Xms40m
-Xmx512m

这里要说一下,Eclipse的JVM启动的时候找JRE的顺序是:
如果eclipse.ini中配置了-vm参数,那么则使用这个参数指定的JRE(jvm.dll库路径);
否则,查看eclipse安装目录下是否有JRE文件夹,如果有的话就使用这个JRE;
否则,去系统注册表中查找安装的JRE,如果还找不到就报错。

所以如果不想卸载掉其他的JDK的话,可以有两种方式:
直接把要使用的JRE文件夹拷贝到Eclipse目录下
修改eclipse.ini文件,添加-vm参数,指定要运行的虚拟机的地址,形如:
-vm
C:\Program Files\Java\jdk1.6.0_12\bin\..\jre\bin\client\jvm.dll

(在eclipse.ini文件中添加配置项时,有空格就换行,不然会当成无效参数)

eclipse.ini文件中:
-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 well
			debug = 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指定到: 安装目录/configuration
					baseConfigurationLocation = 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 2013
org.eclipse.update.reconcile=false
eclipse.p2.profile=epp.package.rcp
osgi.instance.area.default=@user.home/workspace
osgi.framework=file\:plugins/org.eclipse.osgi_3.7.2.v20120110-1415.jar
equinox.use.ds=true
eclipse.buildId=M20120208-0800
osgi.bundles=reference\:file\:org.eclipse.equinox.simpleconfigurator_1.0.200.v20110815-1438.jar@1\:start
org.eclipse.equinox.simpleconfigurator.configUrl=file\:org.eclipse.equinox.simpleconfigurator/bundles.info
eclipse.product=org.eclipse.platform.ide
osgi.splashPath=platform\:/base/plugins/org.eclipse.platform
osgi.framework.extensions=
osgi.bundles.defaultStartLevel=4
eclipse.application=org.eclipse.ui.ide.workbench
eclipse.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 location
			url = getInstallLocation();
			String path = new File(url.getFile(), "plugins").toString(); 
			path = searchFor(framework, path);
			if (url.getProtocol().equals("file")) 
				url = new File(path).toURL();
			else
				url = 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 name
			String 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 ws
				String 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 time
		ensureBundlesActive(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 service
				appLauncher = 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;
		}
	}
  • 大小: 37.5 KB
分享到:
评论

相关推荐

    eclipse启动时间源码

    此外,还可以使用Eclipse的内置性能分析工具(如VisualVM或JProfiler)来监控和分析启动过程中的性能瓶颈,以便针对性地进行调优。 总之,理解Eclipse启动时间源码并掌握JVM调优技术,不仅可以帮助我们提高Eclipse...

    eclipse ide4.7.3源码

    这个版本的Eclipse源码是开发者深入理解其内部工作原理,进行定制化开发或者贡献代码的重要资源。下面将详细讨论Eclipse IDE 4.7.3中的关键知识点。 1. **Eclipse IDE架构**:Eclipse基于插件架构,允许开发者通过...

    eclipse启动计时源码及导出插件

    6. **性能优化**:通过分析启动计时,开发者可以识别哪些操作导致了启动延迟,从而优化代码或调整Eclipse配置以提升启动速度。 7. **版本控制**:版本号中的日期和时间戳可能表示使用了某种版本控制系统,如Git,...

    Eclipse开发技术详解 源码

    "Eclipse开发技术详解 源码" 提供了深入理解Eclipse平台及其开发过程的机会。源码是软件开发的核心,通过阅读和研究源码,开发者可以更深入地了解Eclipse的工作原理,从而提升自己的开发技能。 首先,我们要明确...

    eclipse查看class源码

    总结一下,Eclipse结合JAD插件,可以方便地查看和理解`.class`文件的源码,这对于代码分析、调试和学习第三方库非常有帮助。但要注意,反编译的源码可能与原始源码存在差异,且尊重和遵循开源许可协议,不要对非开源...

    Eclipse-OSGi内核源码分析

    通过对Eclipse OSGi内核源码的分析,我们可以深入理解其工作原理,从而更好地利用它来开发高效、可扩展的应用程序。 1. **模块化系统**:OSGi的核心概念是模块,每个模块(Bundle)包含类、资源和元数据。Bundle...

    Jmeter3.3源码导入eclipse

    《JMeter 3.3 源码分析与二次开发指南》 JMeter,一个强大的开源性能测试工具,被广泛用于测试Web应用的性能和负载。JMeter 3.3 版本是其发展历程中的一个重要里程碑,提供了丰富的功能和优化。在本文中,我们将...

    eclipse cdt9.11源码

    5. **调试器**:CDT内置了强大的C/C++调试器,支持断点设置、变量查看、调用堆栈分析等,使调试过程更加直观和高效。 6. **代码导航**:通过符号索引和跨文件搜索,CDT帮助开发者快速定位和理解代码结构。 7. **...

    Apktool源码,eclipse

    源码的获取和理解对于深入学习Android应用逆向工程、安全分析以及二次开发至关重要。Eclipse是Java开发的常用集成开发环境(IDE),提供了丰富的功能和插件支持,使得代码编写、调试和项目管理变得方便。 本文将...

    Eclipse开发Android源码

    在Android开发过程中,有时需要深入理解系统的工作原理,这时候就需要查看和分析Android的源码。本文将详细介绍如何使用Eclipse这一流行的集成开发环境(IDE)来导入和浏览Android的源码。 首先,Android源码是支持...

    精通Eclipse Web开发 源码

    “基础篇”对Eclipse平台做了简单的介绍,并列举了一些在Web开发过程中经常用到的Eclipse功能;“进阶篇”主要介绍了在Web开发中常用的技术,如Struts、Hibernate、Tomcat、Spring等以及这些技术在Eclipse平台中可能...

    Tomcat8 源码,可以在eclipse中直接运行

    通过在Eclipse集成开发环境中直接运行源码,可以方便地调试和分析Tomcat的执行流程。 首先,我们需要了解Tomcat的基本架构。Tomcat主要由以下几个核心组件构成: 1. **Catalina**:这是Tomcat的核心,负责处理...

    Android4.4Eclipse关联源码

    将Android 4.4源码与Eclipse关联,意味着开发者可以直接在IDE中浏览、搜索和修改源码,这极大地提高了开发效率和学习过程中的直观性。 要将Android源码关联到Eclipse,你需要完成以下步骤: 1. 下载并安装ADT...

    贪吃蛇源码eclipse开发

    通过分析这个源码,你可以深入理解Java GUI编程、多线程、事件处理等重要概念,并且了解如何在Eclipse中进行项目管理和调试。同时,贪吃蛇游戏的逻辑也涉及到了基本的算法设计,对于提升编程思维和问题解决能力非常...

    如何使用Eclipse导入并运行源码

    1. **打开Eclipse**:启动Eclipse IDE。 2. **创建新的Java项目**: - 在菜单栏选择“File” -&gt; “New” -&gt; “Java Project”,或者在Package Explorer视图中右键选择“New” -&gt; “Java Project”。 - 输入项目的...

    eclipse IDE 源码(eclipse IDE本身的源码) 3.6RC4版

    10. **性能优化**:Eclipse 3.6RC4版本在性能上做了很多改进,源码中可以看到如何优化代码以提高启动速度、减少内存消耗和提升整体响应性。 通过研究Eclipse IDE的源码,开发者不仅可以深入了解IDE的内部工作原理,...

    Eclipse项目源码+JSP+MyEclipse----Eclipse初学者的宝典

    1. Eclipse的安装和基本操作:如何启动Eclipse,创建新项目,导入源码,设置编译器和运行环境。 2. JSP基础:理解JSP语法,创建简单的JSP页面,使用内置对象,以及如何调用Servlet。 3. Servlet开发:编写Servlet...

    android 源码 (可与eclipse关联)

    在Android开发过程中,深入理解Android源码对于提升开发效率、优化性能和解决复杂问题具有重要意义。"android 源码 (可与eclipse关联)" 提供的源码库允许开发者直接在Eclipse集成开发环境中(IDE)进行查看和研究,...

    Tomcat7.0源码,可直接导入eclipse

    Eclipse是一款强大的Java开发工具,拥有优秀的代码编辑、调试和项目管理功能,是分析和理解复杂源码的理想平台。 在Eclipse中导入Tomcat源码,可以按照以下步骤进行: 1. 打开Eclipse,选择“File” &gt; “Import”。...

Global site tag (gtag.js) - Google Analytics