专栏首页liulunvscode源码分析【四】程序启动的逻辑,最初创建的服务

vscode源码分析【四】程序启动的逻辑,最初创建的服务

在第一节中提到的startup函数里(src\vs\code\electron-main\main.ts) 有一个createServices的调用:

const services = new ServiceCollection();
		const environmentService = new EnvironmentService(args, process.execPath);
		const instanceEnvironment = this.patchEnvironment(environmentService); // Patch `process.env` with the instance's environment
		services.set(IEnvironmentService, environmentService);
		const logService = new MultiplexLogService([new ConsoleLogMainService(getLogLevel(environmentService)), bufferLogService]);
		process.once('exit', () => logService.dispose());
		services.set(ILogService, logService);
		services.set(IConfigurationService, new ConfigurationService(environmentService.settingsResource));
		services.set(ILifecycleService, new SyncDescriptor(LifecycleService));
		services.set(IStateService, new SyncDescriptor(StateService));
		services.set(IRequestService, new SyncDescriptor(RequestService));
		services.set(IDiagnosticsService, new SyncDescriptor(DiagnosticsService));
		services.set(IThemeMainService, new SyncDescriptor(ThemeMainService));
		services.set(ISignService, new SyncDescriptor(SignService));
		return [new InstantiationService(services, true), instanceEnvironment];

在这个方法里,首先创建了一个ServiceCollection(src\vs\platform\instantiation\common\serviceCollection.ts) 这个ServiceCollection内部其实就是一个map对象;不用细说; 我们先看看这些service都是干嘛的

运行环境服务:EnvironmentService

路径:src\vs\platform\environment\node\environmentService.ts 这是一个工具类, 通过这个类可以获取程序的: 启动目录、日志目录、操作系统、配置文件目录、快捷键绑定配置路径.... 非常多!

多路日志服务:MultiplexLogService

路径:src\vs\platform\log\common\log.ts 默认是用的控制台输出日志(ConsoleLogMainService) 也是一个工具类 包含trace(查看调用堆栈的),debug,info,warn,error,critical 还有dispose(释放日志服务,进程退出的时候回被调用)和setLevel(设置日志级别)的方法; 在同一个文件里,除了ConsoleLogMainService, 还实现了其他几种日志记录方式,不多做介绍了;

配置服务:ConfigurationService

路径:src\vs\platform\configuration\node\configurationService.ts 从运行环境服务(environmentService)里,拿到配置文件的路径 读出配置文件的内容,然后提供配置项的读写功能; 配置项变更的时候,会有相应的事件触发出来;

生命周期服务:LifecycleService

路径:src\vs\platform\lifecycle\electron-main\lifecycleMain.ts 在这里监听了一系列的electron的事件 比如: before-quit、window-all-closed、will-quit等 事件被触发的时候,做了下面一些事情 记日志、屏蔽electron默认的处理逻辑、执行自己的逻辑

状态服务:StateService

路径:src\vs\platform\state\node\stateService.ts 在storage.json里记录一些与程序运行状态有关的键值对(也可以删除)

请求服务:RequestService

路径:src\vs\platform\request\electron-main\requestService.ts 使用electron提供的net.request方法,发起请求(支持代理和SSL)

诊断服务:DiagnosticsService

路径:src\vs\platform\diagnostics\electron-main\diagnosticsService.ts 根据不同的操作系统,计算CPU消耗、内存消耗、GPU消耗等

界面主题服务:ThemeMainService

路径:src\vs\platform\theme\electron-main\themeMainService.ts 获取背景色、设置背景色 数据通过stateService保存

程序签名服务:SignService

路径:src\vs\platform\lifecycle\electron-main\lifecycleMain.ts 这个服务为程序的签名提供帮助 缓存了一个vsda的import,目的是为了解决签名时的一个BUG

实例化服务:InstantiationService

这个服务比较特殊,不是在本文一开始所讲的代码里设置的 前面的代码中有这么一行:

return [new InstantiationService(services, true), instanceEnvironment];

这个服务就是在它自身的内部保存到ServiceCollection

	constructor(services: ServiceCollection = new ServiceCollection(), strict: boolean = false, parent?: InstantiationService) {
		this._services = services;
		this._strict = strict;
		this._parent = parent;
		this._services.set(IInstantiationService, this);
	}

这个服务提供了反射、实例化的一些方法; 用于创建具体的类型的实例

服务的初始化工作

服务的对象创建出来之后,有些服务需要完成初始化才能使用 这是在main.ts的initServices中完成的(src\vs\code\electron-main\main.ts)

		// Environment service (paths)
		const environmentServiceInitialization = Promise.all<void | undefined>([
			environmentService.extensionsPath,
			environmentService.nodeCachedDataDir,
			environmentService.logsPath,
			environmentService.globalStorageHome,
			environmentService.workspaceStorageHome,
			environmentService.backupHome
		].map((path): undefined | Promise<void> => path ? mkdirp(path) : undefined));

		// Configuration service
		const configurationServiceInitialization = configurationService.initialize();

		// State service
		const stateServiceInitialization = stateService.init();

		return Promise.all([environmentServiceInitialization, configurationServiceInitialization, stateServiceInitialization]);

可以看到这个方法里创建了一大堆目录; 创建目录的方法是:(src\vs\base\node\pfs.ts)

const mkdir = async () => {
		try {
			await promisify(fs.mkdir)(path, mode);
		} catch (error) {

			// ENOENT: a parent folder does not exist yet
			if (error.code === 'ENOENT') {
				return Promise.reject(error);
			}

			// Any other error: check if folder exists and
			// return normally in that case if its a folder
			try {
				const fileStat = await stat(path);
				if (!fileStat.isDirectory()) {
					return Promise.reject(new Error(`'${path}' exists and is not a directory.`));
				}
			} catch (statError) {
				throw error; // rethrow original error
			}
		}
	};

另外: 最后几个服务的创建(严格说还没有创建)都用到了SyncDescriptor(src\vs\platform\instantiation\common\descriptors.ts) 这里我们解释一下SyncDescriptor,是个简单的泛型类型; 一个它的实例,可以持有一个类型(传入构造函数的类型),这个类型可以等到用的时候再实例化;

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • vscode源码分析【六】服务实例化和单例的实现

    细心的读者可能会发现,在第四篇文章中的createService方法中,并没有把所有的服务实例化,下面这些服务,只是记了他们的类型: src\vs\code...

    liulun
  • centos安装nginx并配置SSL证书

    配置路径:/etc/nginx/ 日志路径:/var/log/nginx 打开配置文件 在HTTP节点下配置两个server节点,其他不变

    liulun
  • 基于.net开发chrome核心浏览器【三】

    本篇我们讲解怎么用CefGlue开发一个最简单的浏览器 一: CefGlue是建立在Cef项目之上的, Cef项目是C/C++的项目; CefGlue只不过是通...

    liulun
  • 学界 | Jeff Dean新提出机器学习索引替代B-Trees:可提速3倍

    机器之心
  • python 虚拟环境的使用

    python3.3+已经支持虚拟环境,无需安装格外的包,通过以下命令即可创建虚拟环境:

    用户2936342
  • .NET 基金会项目介绍-.NET Micro Framework

    .NET Micro Framework 是属于 .Net 基金会的一个项目,本文将简要介绍该项目相关的信息。

    newbe36524
  • iOS开发-AFNetworking详解

    这是一篇AFNetworking的详细解析 使用示例 新建一个AFHTTPSessionManager的manager,然后用manager请求对应网址的信息,...

    落影
  • 聊一聊 Python 中的“垃圾”回收

    对于python来说,一切皆为对象,所有的变量赋值都遵循着对象引用机制。程序在运行的时候,需要在内存中开辟出一块空间,用于存放运行时产生的临时变量;计算完成后,...

    昱良
  • 设计模式之命令模式-使用命令模式实现遥控器及总结

    public class LightOffCommand  implements ICommandInterface{

    凯哥Java
  • ASP.NET安全隐患的临时解决方法

    前几天的一个安全会议上公布了一个ASP.NET中的安全隐患(在1.0至4.0的版本中均存在),黑客可以使用这个隐患获取到网站的web.config文件(往往保存...

    张善友

扫码关注云+社区

领取腾讯云代金券