附录 A:附录:技术介绍

本附录包含面向开发人员和其他希望详细了解 Spring Shell 如何操作 在内部工作,以及它的设计决策是什么。spring-doc.cn

A.1. 命令注册

定义命令注册是介绍命令结构及其选项的第一步 和参数。这与后面发生的事情松散地解耦,例如解析命令行输入和运行 实际目标代码。从本质上讲,它是向用户显示的命令 API 的定义。spring-doc.cn

A.1.1. 命令

结构中的命令定义为命令数组。这将产生一个 结构,类似于以下示例:spring-shellspring-doc.cn

command1 sub1
command2 sub1 subsub1
command2 sub2 subsub1
command2 sub2 subsub2
如果定义了子命令,我们目前不支持将命令映射到显式父级。 例如,不能同时注册 和 。command1 sub1command1 sub1 subsub1

A.1.2. 交互模式

Spring Shell 被设计为在两种模式下工作:交互式(本质上是 是您在一系列命令中拥有活动 shell 实例的位置)和 非交互式 (命令从命令行逐个执行)。REPLspring-doc.cn

这些模式之间的差异主要在于对可以执行的操作的限制 在每种模式下。例如,显示以前的 stacktrace 是不可行的 如果 shell 不再处于活动状态,则命令的命令。通常,shell 是否仍处于活动状态 指示可用信息。spring-doc.cn

此外,处于活动会话中可能会提供有关用户所经历的更多信息 在活动会话中执行。REPLspring-doc.cn

A.1.3. 选项

选项可以定义为 long 和 short,其中前缀分别为 和 。 以下示例显示了 long 和 short 选项:---spring-doc.cn

CommandRegistration.builder()
	.withOption()
		.longNames("myopt")
		.and()
	.build();
CommandRegistration.builder()
	.withOption()
		.shortNames('s')
		.and()
	.build();

A.1.4. 目标

目标定义命令的执行目标。它可以是 POJO 中的一个方法, a 或 .ConsumerFunctionspring-doc.cn

方法

在现有 POJO 中使用 a 是定义目标的一种方法。 请考虑以下类:Methodspring-doc.cn

public static class CommandPojo {

	String command(String arg) {
		return arg;
	}
}

给定前面清单中显示的现有类,然后你可以注册它的方法:spring-doc.cn

CommandPojo pojo = new CommandPojo();
CommandRegistration.builder()
	.command("command")
	.withTarget()
		.method(pojo, "command")
		.and()
	.withOption()
		.longNames("arg")
		.and()
	.build();
功能

使用 a 作为目标可以灵活地处理 发生在命令执行中,因为您可以使用 a 给定为 a .的返回类型为 然后是打印到 shell 中的内容。请考虑以下示例:FunctionCommandContextFunctionFunctionspring-doc.cn

CommandRegistration.builder()
	.command("command")
	.withTarget()
		.function(ctx -> {
			String arg = ctx.getOptionValue("arg");
			return String.format("hi, arg value is '%s'", arg);
		})
		.and()
	.withOption()
		.longNames("arg")
		.and()
	.build();
消费者

使用 a 与使用 基本相同,区别在于 没有 return 类型。如果你需要将某些东西打印到 shell 中, 您可以从上下文中获取对 a 的引用并打印一些内容 通过它。请考虑以下示例:ConsumerFunctionTerminalspring-doc.cn

CommandRegistration.builder()
	.command("command")
	.withTarget()
		.consumer(ctx -> {
			String arg = ctx.getOptionValue("arg");
			ctx.getTerminal().writer()
				.println(String.format("hi, arg value is '%s'", arg));
		})
	.and()
	.withOption()
		.longNames("arg")
		.and()
	.build();

A.2. 命令解析器

在执行命令之前,我们需要解析命令和用户可能提供的任何选项。解析 介于 Command Registration 和 Command Execution 之间。spring-doc.cn

A.3. 命令执行

当命令解析完成其工作并解决命令注册问题时,命令执行 执行运行代码的艰苦工作。spring-doc.cn

A.4. 命令上下文

该接口允许访问当前正在运行的 上下文。您可以使用它来访问选项:CommandContextspring-doc.cn

String arg = ctx.getOptionValue("arg");

如果你需要将某些内容打印到 shell 中,你可以获取 a 并使用它的 writer 来打印一些内容:Terminalspring-doc.cn

ctx.getTerminal().writer().println("hi");

A.5. 命令目录

该接口定义命令注册在 一个 shell 应用程序。可以动态注册和取消注册 commands,为可能的用例提供了灵活性 命令 来来去去,具体取决于 shell 的状态。请考虑以下示例:CommandCatalogspring-doc.cn

CommandRegistration registration = CommandRegistration.builder().build();
catalog.register(registration);

A.5.1. 命令解析器

您可以实现该接口并定义一个 Bean 以动态 解析从命令名称到其实例的映射。考虑 以下示例:CommandResolverCommandRegistrationspring-doc.cn

static class CustomCommandResolver implements CommandResolver {
	List<CommandRegistration> registrations = new ArrayList<>();

	CustomCommandResolver() {
		CommandRegistration resolved = CommandRegistration.builder()
			.command("resolve command")
			.build();
		registrations.add(resolved);
	}

	@Override
	public List<CommandRegistration> resolve() {
		return registrations;
	}
}
a 的当前限制是每次解析命令时都会使用它。 因此,如果命令解析调用需要很长时间,我们建议不要使用它,因为它会 使 shell 感觉迟钝。CommandResolver

A.5.2. 命令目录定制器

您可以使用该界面自定义 . 它的主要用途是修改目录。此外,在自动配置中,此 接口用于将现有 bean 注册到目录中。 请考虑以下示例:CommandCatalogCustomizerCommandCatalogspring-shellCommandRegistrationspring-doc.cn

static class CustomCommandCatalogCustomizer implements CommandCatalogCustomizer {

	@Override
	public void customize(CommandCatalog commandCatalog) {
		CommandRegistration registration = CommandRegistration.builder()
			.command("resolve command")
			.build();
		commandCatalog.register(registration);
	}
}

你可以创建一个 as bean,Spring Shell 会处理其余的工作。CommandCatalogCustomizerspring-doc.cn

A.6. 主题

主题中的样式是通过使用 AttributedString from 来提供的。 不幸的是,样式设置大多没有记录,但我们尝试通过 它的一些功能在这里。JLineJLinespring-doc.cn

在样式规范中,是一个具有特殊格式的字符串。可以给出 spec 如果用逗号分隔,则多次。规范将为 foreground、background 或其模式。特殊格式允许 如果前者由于某种原因无效,则在后一个规范中定义一个默认值。JLine<spec>:=<spec>spring-doc.cn

如果 spec 包含冒号,则其前部分表示前景或背景 可能的值为 、 或 。没有 rbg 的 color 值 是允许的颜色 、 、 或 的名称。颜色的短格式分别为 、 、 、 、 和 。如果 color 以 或 为前缀,则亮色模式会自动 应用的。前缀 with 将从 JLine 内部 bsd 颜色表中解析。foregroundfgfbackgroundbgbforeground-rgbfg-rgbf-rgbbackground-rgbbg-rgbb-rgbblackredgreenyellowbluemagentacyanwhitekrgybmcw!bright-~spring-doc.cn

如果 rgb 格式是预期的,并且前缀为 either 或 normal 使用十六进制格式。x#spring-doc.cn

fg-red
fg-r
fg-rgb:red
fg-rgb:xff3333
fg-rgb:#ff3333

如果 spec 包含特殊名称 、 、defaultboldfaintitalicunderlineblinkinverseinverse-neginversenegconcealcrossed-outcrossedouthiddenspring-doc.cn

bold
bold,fg:red

如果 spec 是一个或多个用分号分隔的数字,则 format 是 ansi 的纯部分 ASCII 代码。spring-doc.cn

31
31;1
解析以 dot 开头的 spec 的 JLine 特殊映射格式不能是 使用,因为我们还没有将它们映射到 Spring Shell 样式名称中。