阿里云发布 Spring Boot 新脚手架,真香 (4)

生成具体的 Demo 代码:继续以 OSSDemoCodeContributor 为例,它是一个 ProjectContributor ,会在项目文件空间创建完成了调用。我们需要为这个 Contributor 在实例化时增加生成过程中需要的元数据信息,例如 ProjectDescription 。

代码生成过程,比较简单,可以直接复用框架中就提供的 mstache 模板引擎。

我们直接将 Demo 代码,以模板的形式,放置在 resources 文件夹之下:

5.png

然后,我们再通过模板引擎,解析这些模板文件,再拷贝到项目目录下即可:

private void writeCodeFile(TemplateRenderer templateRenderer, Language langeuage, Map<String, Object> params, Path path, String temp) throws IOException { ...... Path pkgPath = 生成包路径 Path filePath = 成成代码文件路径 // 渲染模板 String code = templateRenderer.render(temp, params); // demo 文件写入 Files.createDirectories(pkgPath); Files.write(filePath, code.getBytes("UTF-8")); }

除了模板代码以外,我们通常还需要在 applicatioin.properties 文件写入模块的配置信息。

这里,我们依然可以使用代码生成的方式:创建模板、解析模板,追加文件的方式来实现。具体代码这里就不贴了,读者可以自己发挥。

原理篇

原理篇,主要介绍 spring.initializr 是如何实现项目工程构建的,以及作为一个框架,如何提供丰富的扩展能力的。

在原理篇,我们将 initializr 的执行分为两个阶段:启动阶段和生成阶段。

启动阶段:启动应用,加载配置,扩展信息初始化;

生成阶段:一个项目生成,从收到请求,到返回内容的完整流程。

1. 启动阶段

再开始启动流程之前,先要看一下 initializr 的扩展体系。

整个架构大量使用了 spring 的 spi 机制,我们来看一下一共有哪些 spring.factories :

initializr-generator/src/main/resources/META-INF/spring.factories

initializr-generator-spring/src/main/resources/META-INF/spring.factories

initializr-web/src/main/resources/META-INF/spring.factories

initializr-actuator/src/main/resources/META-INF/spring.factories

start-site/src/main/resources/META-INF/spring.factories

其中只有一个在 start.spring.io 中,其他 4 个都在 initializr 工程中(各 spring.factories 的具体内容见参考资料)。

不过要注意,这些 spring.factories 定义,仅仅代表了各个 SPI 有哪些扩展。不同spi的实现创建和使用完全是在不同的阶段进行的。

在应用启动阶段,其实只有一个 spi 会被加载(暂不考虑 actuator):io.spring.initializr.web.autoconfigure.InitializrAutoConfiguration 。

@Configuration @EnableConfigurationProperties(InitializrProperties.class) public class InitializrAutoConfiguration { @Bean @ConditionalOnMissingBean public ProjectDirectoryFactory projectDirectoryFactory() @Bean @ConditionalOnMissingBean public IndentingWriterFactory indentingWriterFactory() @Bean @ConditionalOnMissingBean(TemplateRenderer.class) public MustacheTemplateRenderer templateRenderer(Environment environment, ObjectProvider<CacheManager> cacheManager) @Bean @ConditionalOnMissingBean public InitializrMetadataUpdateStrategy initializrMetadataUpdateStrategy(RestTemplateBuilder restTemplateBuilder, ObjectMapper objectMapper) @Bean @ConditionalOnMissingBean(InitializrMetadataProvider.class) public InitializrMetadataProvider initializrMetadataProvider(InitializrProperties properties, InitializrMetadataUpdateStrategy initializrMetadataUpdateStrategy) @Bean @ConditionalOnMissingBean public DependencyMetadataProvider dependencyMetadataProvider() @Configuration @ConditionalOnWebApplication static class InitializrWebConfiguration { @Bean InitializrWebConfig initializrWebConfig() @Bean @ConditionalOnMissingBean ProjectGenerationController<ProjectRequest> projectGenerationController( InitializrMetadataProvider metadataProvider, ApplicationContext applicationContext) @Bean @ConditionalOnMissingBean ProjectMetadataController projectMetadataController(InitializrMetadataProvider metadataProvider, DependencyMetadataProvider dependencyMetadataProvider) @Bean @ConditionalOnMissingBean CommandLineMetadataController commandLineMetadataController(InitializrMetadataProvider metadataProvider, TemplateRenderer templateRenderer) @Bean @ConditionalOnMissingBean SpringCliDistributionController cliDistributionController(InitializrMetadataProvider metadataProvider) } }

这里会做如下几件事情:

初始化元数据 Provider

创建模板引擎

创建目录、缩进工厂

初始化 web 配置

创建 spring mvc 的 web 入口

各种 ProjectGenerationController

其中最关键的元数据加载部分,使用了 EnableConfigurationProperties 注解,将 spring 环境中的配置项写到 InitializrProperties 上:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zwpzdz.html