搭建一个影视网站,创意logo设计图片欣赏,wordpress前端框架,某企业网站搜索引擎优化作者 | 良名 阿里巴巴技术专家背景相信很多人都使用过 start.spring.io 来初始化自己的 Spring Boot 工程#xff0c;这个工具为开发者提供了丰富的可选组件#xff0c;并且可以选择多种打包方式#xff0c;大大方便了开发人员的使用。最近#xff0c;阿里的 Nacos、Senti… 作者 | 良名 阿里巴巴技术专家背景相信很多人都使用过 start.spring.io 来初始化自己的 Spring Boot 工程这个工具为开发者提供了丰富的可选组件并且可以选择多种打包方式大大方便了开发人员的使用。最近阿里的 Nacos、Sentinel 也进入 start.spring.io 的选项中进一步的方便开发者使用阿里云的产品。但是生成的工程骨架中只有组件坐标信息缺少对应的使用方法和 Demo 代码于是开发者还是需要去寻找相关使用教程或者样例代码如果找的不对或者是版本不匹匹配还需要花费不少时间去排查和解决问题这些问题都在无形中增加用户的工作量。我们将对软件工程的抽象层次自上而下进行切分会得到如下的几个层级行业、解决方案、应用、功能、组件明显的 start.spring.io 目前只能提供组件级别的支持。再将组件这层展开会发现这样一个生命周期组件引入、组件配置、功能开发、线上运维。start.spring.io 也只实现了“组件引入”这一功能。我们的目标是“让阿里云成为广大 Java 开发者最好用的云”。要实现这个目标是否可以再向前走几步在解决“组件引入”问题的基础上将组件的典型使用方法、样例代码、使用说明也加入到工程中呢基于这种思考我们上线了自己的 bootstrap 站点 start.aliyun.com https://start.aliyun.com/当然本着不重复造轮子的原则我们不再构建一套工程生成底层框架而是使用 Spring Initializr 来实现这部分功能。在此之上专注于增加新特性实现服务广大开发者的目标。Spring Initializrhttps://github.com/spring-io/initializr在 start.aliyun.com 中我们为广大开发者带来了如下便利特性为每个组件提供了单独的 DemoCode 和对应的配置样例(本次已发布)工程内置说明减少用户查找文档的困难(部分实现)开发者只需要做减法而非加法的使用方式(部分实现)提供多组件集成的解决方案(开发中)定期跟进 start.spring.io 的更新方便大家使用到 spring 的最新功能。start.aliyun.comhttps://start.aliyun.com/未来我们还需要再助力开发者这条路上继续发力不仅仅是做好组件集成的工作还要需要继续向上支持提供更多功能、服务、应用层级的快速构建能力。本文围绕 spring initializr 框架以 start.spring.io 为例全面的给大家介绍如何使用和扩展这个框架以及背后的运行原理。使用篇由于 spring-initializr 提供了灵活的扩展能力以及丰富的默认实现其使用方式也是非常的灵活多变为了便于说明我们直接通过 start.spring.io 看看 Spring 自己是怎么使用这套框架的。1. 基本用法基本用法的原则是尽量少写代码甚至是不写代码。只通过配置就可以实现 initializr 工程的创建。依赖引入要使用 spring-initializr 首先要引入这套框架。很简单直接依赖 bom 即可dependencyManagement dependencies dependency groupIdio.spring.initializrgroupId artifactIdinitializr-bomartifactId version0.9.0.BUILD-SNAPSHOTversion typepomtype scopeimportscope dependency dependenciesdependencyManagement有了这个 bom 依赖我们就不用再关心内部组件的版本等信息了。一般来说我们还需要引入具体组件dependency groupIdio.spring.initializrgroupId artifactIdinitializr-generator-springartifactId dependency dependency groupIdio.spring.initializrgroupId artifactIdinitializr-version-resolverartifactId dependency dependency groupIdio.spring.initializrgroupId artifactIdinitializr-webartifactId dependency具体每个子模块的用途这里列出来供读者参考initializr-actuator: 监控诊断的附加信息这个暂时忽略initializr-bom: 便于外部使用的bom依赖initializr-docs: 使用文档initializr-generator: 核心工程生成库initializr-generator-spring: 用于生成典型的spring boot工程initializr-generator-test: 测试框架initializr-metadata: 项目各个方面的元数据基础结构initializr-service-sample: 基本使用案例initializr-version-resolver:版本号解析能力initializr-web: 提供给三方客户端使用的web入口。基本配置完成了框架引入就需要做一些基础配置了支持哪些语言Java、groovy、Kotlin支持哪些版本1.8、11、13支持哪些打包方式jar、war将这些信息全部配置到 application.yml 文件中如下initializr: packagings: - name: Jar id: jar default: true - name: War id: war default: false javaVersions: - id: 13 default: false - id: 11 default: false - id: 1.8 name: 8 default: true languages: - name: Java id: java default: true - name: Kotlin id: kotlin default: false - name: Groovy id: groovy default: false其中 name 是可选的 id 是必填的。每个配置项下可以有一个默认值(将 default 这是为 true 即可)除了这些基本配置我们还需要定义可以支持的项目类型initializr: types: - name: Maven Project id: maven-project description: Generate a Maven based project archive. tags: build: maven format: project default: true action: /starter.zip - name: Maven POM id: maven-build description: Generate a Maven pom.xml. tags: build: maven format: build default: false action: /pom.xml - name: Gradle Project id: gradle-project description: Generate a Gradle based project archive. tags: build: gradle format: project default: false action: /starter.zip - name: Gradle Config id: gradle-build description: Generate a Gradle build file. tags: build: gradle format: build default: false action: /build.gradle默认情况下 initializr 已经支持 4 种项目类型/pom.xml 生成一个 Maven 的 pom.xml 配置文件/build.gradle 生成 Gradle 的配置文件/starter.zip 生成 zip 方式压缩的工程文件/starter.tgz 生成以 tgz 方式压缩的工程文件通过 tags 标签我们可以定义不同配型的编译方式 (build) 和打包格式(format)。配置基本依赖完成了基本配置以后就可以配置可选的依赖组件了。依赖配置以 dependency 为 key 同样配置在 application.yml 的 initializr 下面这里给出一个简单的样例initializr: dependencies: - name: Web content: - name: Web id: web description: Full-stack web development with Tomcat and Spring MVC - name: Developer Tools content: - name: Spring Boot DevTools id: devtools groupId: org.springframework.boot artifactId: spring-boot-devtools description: Provides fast application restarts, LiveReload, and configurations for enhanced development experience. - name: Lombok id: lombok groupId: org.projectlombok artifactId: lombok description: Java annotation library which helps to reduce boilerplate code.dependencies 下定义分组。分组的作用是便于展示和快速查找所以不需要 id 只需要 name 信息每个分组的 content 是分组的具体内容也就是这个分组下的组件定义支持以列表形式定义多个另外每个分组都可以设置当前分组内组件公用的配置信息。每一依赖包含如下的基本信息id组件的唯一标识符groupId artifactId组件的坐标name显示名称description描述信息主要用于展示用途version组件版本关于 groupId artifactId如果设置了坐标生成的项目里会使用这里的坐标定位组件但是如果没有设置坐标框架会认为这是一个标准的 spring-boot 组件自动添加 spring-boot-starter-{id} 作为生成的依赖坐标。关于 version如果直接在组件上设置版本信息框架会直接使用这个值作为组件依赖的版本但是很多时候组件的版本会受到 spring-boot 版本的影响此时就需要对版本做特殊的定义 管理。配置依赖版本管理这里需要先了解一下版本命名规则一个典型的版本一般包含如下 4 个信息大版本、小版本、修正版本、版本限定符。版本范围有一个上界和下界可以方括号 [] 或者圆括号 () 表示。方括号代表上下界的闭区间圆括号代表上下界的开区间。例如“[1.1.6.RELEASE,1.3.0.M1)”代表所有从 1.1.6.RELEASE 到 1.3.0.M1 之间所有的版本(包含 1.1.6.RELEASE 但不包含 1.3.0.M1 )。同时可以使用单一版本号作为版本范围例如 “1.2.0.RELEASE”。单一版本号的版本范围代表“从这个版本以及之后的所有版本”。如果需要使用“最新的 Release 版本”的概念可以使用一个字母 x 代表具体的版本号。例如 1.4.x.BUILD-SNAPSHOT 代表 1.4.x 的最新快照版本。再比如如果需要表达从 1.1.0.RELEASE 到 1.3.x 之间的所有版本可以用[1.1.0.RELEASE,1.3.x.RELEASE]来表达。另外版本限定符也是有顺序的(升序)M里程碑版本RC发布候选版本RELEASE发布版本BUILD-SNAPSHOT为开发构建的快照版本所以快照版本是所有限定符里优先级最高的。假设某个组件需要 Spring Boot 的最新版本可以使用 1.5.x.BUILD-SNAPSHOT (假设 1.5 版是 Spring Boot 的最新版本)。最后版本范围中讨论的版本指的都是 Spring Boot的版本而不是组件自己的版本。前面介绍了可以使用 version 属性定义组件的具体版本号但是如果组件版本与Spring Boot 的版本存在关联关系就需要使用 compatibilityRange 来配置依赖的版本范围。compatibilityRange 可以定义在两个地方直接定义在组件(或 Bom )上这种定义方式代表组件只支持 Spring Boot 的某一个版本范围例如下面的配置initializr: dependencies: - name: Stuff content: - name: Foo id: foo ... compatibilityRange: 1.2.0.M1 - name: Bar id: bar ... compatibilityRange: [1.5.0.RC1,2.0.0.M1)Foo 可以支持 Spring boot 1.2.0 之后的所有版本而Bar只能支持 Spring Boot 1.5.0 到 2.0.0 之间的版本且不包含 2.0.0 定义在组件的 mappgin 属性下可以支持在 Spring Boot 不同版本之下对组件做不同的设置(可以重置组件部分或者是所有的属性)下面的例子中对 artifactId 做了特殊定义initializr: dependencies: - name: Stuff content: - name: Foo id: foo groupId: org.acme.foo artifactId: foo-spring-boot-starter compatibilityRange: 1.3.0.RELEASE mappings: - compatibilityRange: [1.3.0.RELEASE,1.3.x.RELEASE] artifactId: foo-starter - compatibilityRange: 1.4.0.RELEASE这个例子中 foo 在 Spring Boot 的 1.3 使用 foo-starter 作为坐标的 artifactId 在 1.4.0.RELEASE 以及之后的版本中还是使用 foo-spring-boot-starter 作为 artifactId 的值使用 Bom 管理版本有时候需要使用 Bom 的方式管理组件版本此时不需要对组件单独设置版本号。要使用 Bom 首先要配置 Bom 定义initializr: env: boms: my-api-bom: groupId: org.acme artifactId: my-api-dependencies version: 1.0.0.RELEASE repositories: my-api-repo-1注意Bom 信息定义在 initializr.env.boms下面。其属性和依赖组件基本一致都是坐标、版本同时 Bom 也支持版本范围管理。完成了 Bom 的定义就需要在组件中引用 Bom initializr: dependencies: - name: Other content: - name: My API id : my-api groupId: org.acme artifactId: my-api bom: my-api-bom一旦用户选择了 my-api 组件框架会自动为生成的项目添加了 my-api-dependencies 的 Bom 依赖2. 高级定制启用缓存如果你启动过 start.spring.io 项目你会在日志里发现这样的输出 “Fetching boot metadata from spring.io/project_metadata/spring-boot” 为了避免过于频繁的检查 Spring Boot 版本官方是建议配合缓存一起使用。首先需要引入缓存框架dependency groupIdjavax.cachegroupId artifactIdcache-apiartifactIddependencydependency groupIdorg.ehcachegroupId artifactIdehcacheartifactIddependency然后在 SpringBootApplication 类上增加 EnableCaching 注解:如果需要自己定义缓存可以调整如下缓存配置增加 Demo代码由于不同的组件有不同的功能如果需要为项目增加 Demo 代码。为不同的组件增加独立配置还记得原理篇中提到的 spring.factories 吗对我们要增加自己的配置项就需要在这里增加针对不同组件样例代码的扩展入口。io.spring.initializr.generator.project.ProjectGenerationConfiguration\com.alibaba.alicloud.initializr.extension.dependency.springboot.SpringCloudProjectGenerationConfiguration在 SpringCloudProjectGenerationConfiguration 中我们通过 ConditionalOnRequestedDependency 注解来识别不同组件ProjectGenerationConfigurationpublic class SpringCloudAlibabaProjectGenerationConfiguration { private final InitializrMetadata metadata; private final ProjectDescription description; private final IndentingWriterFactory indentingWriterFactory; private final TemplateRenderer templateRenderer; public SpringCloudAlibabaProjectGenerationConfiguration(InitializrMetadata metadata, ProjectDescription description, IndentingWriterFactory indentingWriterFactory, TemplateRenderer templateRenderer) { this.metadata metadata; this.description description; this.indentingWriterFactory indentingWriterFactory; this.templateRenderer templateRenderer; } Bean ConditionalOnRequestedDependency(sca-oss) public OSSDemoCodeContributor ossContributor() { return new OSSDemoCodeContributor(description, templateRenderer); } ......}上面的代码会在选择了 sca-oss 组件时创建一个 OSSDemoCodeContributor 用于对应 Demo 代码的生成。生成具体的 Demo 代码继续以 OSSDemoCodeContributor 为例它是一个 ProjectContributor 会在项目文件空间创建完成了调用。我们需要为这个 Contributor 在实例化时增加生成过程中需要的元数据信息例如 ProjectDescription 。代码生成过程比较简单可以直接复用框架中就提供的 mstache 模板引擎。我们直接将 Demo 代码以模板的形式放置在 resources 文件夹之下然后我们再通过模板引擎解析这些模板文件再拷贝到项目目录下即可 private void writeCodeFile(TemplateRenderer templateRenderer, Language langeuage, MapString, 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.factoriesinitializr-generator-spring/src/main/resources/META-INF/spring.factoriesinitializr-web/src/main/resources/META-INF/spring.factoriesinitializr-actuator/src/main/resources/META-INF/spring.factoriesstart-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 。ConfigurationEnableConfigurationProperties(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)BeanConditionalOnMissingBeanpublic InitializrMetadataUpdateStrategy initializrMetadataUpdateStrategy(RestTemplateBuilder restTemplateBuilder, ObjectMapper objectMapper)BeanConditionalOnMissingBean(InitializrMetadataProvider.class)public InitializrMetadataProvider initializrMetadataProvider(InitializrProperties properties, InitializrMetadataUpdateStrategy initializrMetadataUpdateStrategy)BeanConditionalOnMissingBeanpublic DependencyMetadataProvider dependencyMetadataProvider()ConfigurationConditionalOnWebApplication static class InitializrWebConfiguration {Bean InitializrWebConfig initializrWebConfig()BeanConditionalOnMissingBean ProjectGenerationController projectGenerationController( InitializrMetadataProvider metadataProvider, ApplicationContext applicationContext)BeanConditionalOnMissingBean ProjectMetadataController projectMetadataController(InitializrMetadataProvider metadataProvider, DependencyMetadataProvider dependencyMetadataProvider)BeanConditionalOnMissingBean CommandLineMetadataController commandLineMetadataController(InitializrMetadataProvider metadataProvider, TemplateRenderer templateRenderer)BeanConditionalOnMissingBean SpringCliDistributionController cliDistributionController(InitializrMetadataProvider metadataProvider) }}这里会做如下几件事情初始化元数据 Provider创建模板引擎创建目录、缩进工厂初始化 web 配置创建 spring mvc 的 web 入口各种 ProjectGenerationController其中最关键的元数据加载部分使用了 EnableConfigurationProperties 注解将 spring 环境中的配置项写到 InitializrProperties 上在 application.yml 文件中可以找到如下的配置信息这里就是实际的项目依赖关系元数据的配置存储点整体来看启动阶段的动作还是比较简单的这也是为什么 start.spring.io 启动只需要数秒的原因。更多的逻辑都被留在了工程生成阶段。2. 生成阶段生成阶段spring-initializr 使用了一个很有意思的实现方式initializr 框架会为每一次项目生成创建一个独立的 context 用于存放生成流程中需要使用到的各种 bean 。先来一张时序图蓝色的类是在应用启动阶段就完成了创建和数据填充其生命周期和整个应用一致黄色的类会在具体的项目构建过程中生成其生命周期在一次项目生成流程之内结束。从上面的时序图中可以看出一个典型的创建行为通常从 ProjectGenerationController收到web端的创建请求开始通过 ProjectGenerationInvoker 这个中间层转换最终进入 ProjectGenerator 的核心构建流程。主干流程下图是 ProjectGenerator 的核心构建流程106 行通过 contextFactory 构建了一个新的 ProjectGenerationContext 。看一下这个context的继承关系原来于spring提供的AnnotationConfigApplicationContext 。再结合 110 行的 refresh() 方法是不是发现了什么就是 spring 的 ApplicationContext 的刷新流程。107 行的 resolve 方法向 context 中注册了一个 ProjectDescription的Provider代码如下由于注册的是 Provider 所以这段逻辑会在 Context 执行 refresh 时运行。这里的 ProjectDescriptionCustomizer 就是针对 ProjectDescription 的扩展用于对用户传入的 ProjectDescription 做调整。这里主要是一些强制依赖关系的调整例如语言版本等。这时候再看 108 行这里向 Context 注册一个 Configuration 。那么这个这个 Configuration 包含了什么内容呢一起来看下面这段代码ProjectGenerationConfiguration前面提到的 spring.factories 中有很多这个 SPI 的实现(参见参考资料)。原来initializr 的整个扩展体系在这里才开始创建实例ProjectGenerator 的 109 行对一个 consumer 做了 accept 操作其实就是调用了下面的代码这里通过 setParent 将应用的主上下文设置为这次 ProjectGenerationContext 的父节点。并且向这次 ProjectGenerationContext 中注册了元数据对象。最后在 ProjectGenerator 的 112 行调用了 projectAssetGenerator 的 generate 方法实现如下通过上面的代码可以发现这里对实际的工程构建工作其实就是很多的 ProjectContributor 共同叠加至此主干流程已经结束了。我们可以发现在主干流程中没有做任何写文件的操作(只创建了根文件夹)它仅仅是定义了一套数据加载、扩展加载的机制与流程将所有的具体实现都作为扩展的一部分。扩展流程spring-initializr 提供了 2 种主要扩展途径ProjectContributor 和 xxxxxCustomizer。从方法签名就可以看出入参只有一个项目的根路径其职责就是向这个路径下些人项目文件。这个扩展点非常的灵活几乎可以支持任何的代码、配置文件写入工作。实现过程中可以通过 ProjectGenerationContext 获取相关依赖然后通过自定义逻辑完成文件生成工作。下面是 initializr 和 start.spring.io 提供的 ProjectContributor 实现拿几个主要的实现看看MavenBuildProjectContributor写入 maven 项目 pom.xml 文件WebFoldersContributor创建 web 项目的资源文件夹ApplicationPropertiesContributor写入 application.properties 文件MainSourceCodeProjectContributor写入应用入口类 xxxApplication.java 文件HelpDocumentProjectContributor写入帮助文档 HELP.md 文件。相对于 ProjectContributorxxxxxCustomizer 不是一个统一的接口我把他理解为一种感念和与之对应的命名习惯每个 Customizer 都有自己明确的名字同时也对应了明确的触发逻辑和职责边界。下面列出框架提供的 Customizer 的说明MainApplicationTypeCustomizer自定义 MainApplication 类MainCompilationUnitCustomizer自定义 MainApplication 编译单元MainSourceCodeCustomizer自定义 MainApplication 源码BuildCustomizer自定义项目构建工具的配置内容GitIgnoreCustomizer自定义项目的 .gitignore 文件HelpDocumentCustomizer自定义项目的帮助文档InitializrMetadataCustomizer自定义项目初始化配置元数据这个 Customizer 比较特殊框架会在首次加载元数据配置时调用ProjectDescriptionCustomizer自定义 ProjectDescription 即在生成项目文件之前允许调整项目描述信息ServletInitializerCustomizer自定义 web 应用在类上的配置内容TestApplicationTypeCustomizer自定义测试 Application 类TestSourceCodeCustomizer自定义测试 Application 类的源码。参考资料1. 相关链接initializr 说明文档https://docs.spring.io/initializr/docs/current-SNAPSHOT/reference/html/spring-initializr 项目地址https://github.com/spring-io/initializrstart.spring.io 项目地址https://github.com/spring-io/start.spring.io2. spring.factories 明细initializr-generator/src/main/resources/META-INF/spring.factoriesio.spring.initializr.generator.buildsystem.BuildSystemFactory\io.spring.initializr.generator.buildsystem.gradle.GradleBuildSystemFactory,\io.spring.initializr.generator.buildsystem.maven.MavenBuildSystemFactoryio.spring.initializr.generator.language.LanguageFactory\io.spring.initializr.generator.language.groovy.GroovyLanguageFactory,\io.spring.initializr.generator.language.java.JavaLanguageFactory,\io.spring.initializr.generator.language.kotlin.KotlinLanguageFactoryio.spring.initializr.generator.packaging.PackagingFactory\io.spring.initializr.generator.packaging.jar.JarPackagingFactory,\io.spring.initializr.generator.packaging.war.WarPackagingFactoryinitializr-generator-spring/src/main/resources/META-INF/spring.factoriesio.spring.initializr.generator.project.ProjectGenerationConfiguration\io.spring.initializr.generator.spring.build.BuildProjectGenerationConfiguration,\io.spring.initializr.generator.spring.build.gradle.GradleProjectGenerationConfiguration,\io.spring.initializr.generator.spring.build.maven.MavenProjectGenerationConfiguration,\io.spring.initializr.generator.spring.code.SourceCodeProjectGenerationConfiguration,\io.spring.initializr.generator.spring.code.groovy.GroovyProjectGenerationConfiguration,\io.spring.initializr.generator.spring.code.java.JavaProjectGenerationConfiguration,\io.spring.initializr.generator.spring.code.kotlin.KotlinProjectGenerationConfiguration,\io.spring.initializr.generator.spring.configuration.ApplicationConfigurationProjectGenerationConfiguration,\io.spring.initializr.generator.spring.documentation.HelpDocumentProjectGenerationConfiguration,\io.spring.initializr.generator.spring.scm.git.GitProjectGenerationConfigurationinitializr-web/src/main/resources/META-INF/spring.factoriesorg.springframework.boot.autoconfigure.EnableAutoConfiguration\io.spring.initializr.web.autoconfigure.InitializrAutoConfigurationorg.springframework.boot.env.EnvironmentPostProcessor\io.spring.initializr.web.autoconfigure.CloudfoundryEnvironmentPostProcessorinitializr-actuator/src/main/resources/META-INF/spring.factoriesorg.springframework.boot.autoconfigure.EnableAutoConfiguration\io.spring.initializr.actuate.autoconfigure.InitializrActuatorEndpointsAutoConfiguration,\io.spring.initializr.actuate.autoconfigure.InitializrStatsAutoConfigurationstart-site/src/main/resources/META-INF/spring.factoriesio.spring.initializr.generator.project.ProjectGenerationConfiguration\io.spring.start.site.extension.build.gradle.GradleProjectGenerationConfiguration,\io.spring.start.site.extension.build.maven.MavenProjectGenerationConfiguration,\io.spring.start.site.extension.dependency.DependencyProjectGenerationConfiguration,\io.spring.start.site.extension.dependency.springamqp.SpringAmqpProjectGenerationConfiguration,\io.spring.start.site.extension.dependency.springboot.SpringBootProjectGenerationConfiguration,\io.spring.start.site.extension.dependency.springcloud.SpringCloudProjectGenerationConfiguration,\io.spring.start.site.extension.dependency.springdata.SpringDataProjectGenerationConfiguration,\io.spring.start.site.extension.dependency.springintegration.SpringIntegrationProjectGenerationConfiguration,\io.spring.start.site.extension.dependency.springrestdocs.SpringRestDocsProjectGenerationConfiguration,\io.spring.start.site.extension.description.DescriptionProjectGenerationConfiguration,\io.spring.start.site.extension.code.kotin.KotlinProjectGenerationConfiguration作者信息陈曦(花名良名)阿里巴巴技术专家。目前在应用容器服务框架团队Spring Cloud Alibaba 项目成员致力于将阿里云打造为Java开发者最好用的云。2014 年加入 B2B多次参与 双11、618 作战。戳原文立即预约直播