start.sping.io代码研读及二次开发

   Spring是Java开发者的圣经,https://spring.io官网作为布道场。开发者几乎能在上面找到关于Spring的一切信息,当然也包括官方推荐项目代码规范。其中https://start.spring.io既是官方的手脚架工程,也常被初学者用来生成入门工程。这个站点也是一个开源Spring项目,颇有些自举的骄傲(Git也有这种骄傲)。国内大厂某云平台也发布了定制化版本。

相关资源

项目列表

官网文档

本地构建

   国内很多开发者会构建本地版本作为加速镜像,这也是start.spring.io项目最常用的功能。

   这项目带有https://start.spring.io前端界面的配置化Spring Initializr 实例。包含下列模块:

  • start-client: 前端界面
  • start-site: 后端基础服务和元数据配置
  • start-site-verification: 元数据测试用例

   执行./mvnw clean install生成target/start-site-exec.jar即可运行。值得借鉴的是frontend-maven-plugin插件,通过maven插件来代替shell脚本,更显规范。

<plugin>
	<groupId>com.github.eirslett</groupId>
	<artifactId>frontend-maven-plugin</artifactId>
	<executions>
		<execution>
			<id>install node and yarn</id>
			<goals>
				<goal>install-node-and-yarn</goal>
			</goals>
			<configuration>
				<nodeVersion>v12.13.0</nodeVersion>
				<yarnVersion>v1.22.4</yarnVersion>
			</configuration>
		</execution>
		<execution>
			<id>yarn install</id>
			<goals>
				<goal>yarn</goal>
			</goals>
		</execution>
		<execution>
			<id>yarn build</id>
			<goals>
				<goal>yarn</goal>
			</goals>
			<configuration>
				<arguments>build</arguments>
			</configuration>
		</execution>
	</executions>
</plugin>

   start-client项目会将静态资源打包成start-client-0.0.1-SNAPSHOT.jar,然后被start-site项目引入。

代码研读

   拜读官方文档可知,start.spring.io项目只是门面,initializr才是里子。initializr文档介绍项目结构:

  • initializr-actuator: optional module to provide additional information and statistics on project generation.

  • initializr-bom: provides a Bill of Materials for easier dependency management in your project.

  • initializr-docs: documentation.

  • initializr-generator: core project generation library.

  • initializr-generator-spring: optional module defining the conventions for a typical Spring Boot project. Can be reused or replaced by your own conventions.

  • initializr-generator-test: test infrastructure for project generation.

  • initializr-metadata: metadata infrastructure for various aspects of the project.

  • initializr-service-sample: showcases a basic custom instance.

  • initializr-version-resolver: optional module to extract version numbers from an arbitrary POM.

  • initializr-web: web endpoints for third party clients.

为了了解生成原理,主要看 initializr-generator and initializr-generator-springinitializr-generator中的ProjectGenerator类是项目生成的单元。

public <T> T generate(ProjectDescription description, ProjectAssetGenerator<T> projectAssetGenerator)
		throws ProjectGenerationException {
    
    
	try (ProjectGenerationContext context = this.contextFactory.get()) {
    
    
		registerProjectDescription(context, description);
		registerProjectContributors(context, description);
		this.contextConsumer.accept(context);
		context.refresh();
		try {
    
    
			return projectAssetGenerator.generate(context);
		}
		catch (IOException ex) {
    
    
			throw new ProjectGenerationException("Failed to generate project", ex);
		}
	}
}

   首先在/src/main/resources/META-INF/spring.factories文件注册配置文件,然后通过@ProjectGenerationConfiguration注解扫描获取配置,然后遍历执行其中的配置项生成代码。

二次开发

   官方文档预留了丰富的扩展接口,详见6.1.1节。具体实现就是追加或重写配置文件,对于应用级开发直接在start.spring.io项目内开发。
在这里插入图片描述

关键代码

  • FcsGenerationConfiguration.java
@ProjectGenerationConfiguration
public class FcsGenerationConfiguration {
    
    
	@Bean
	public FcsContributor fcsContributor(ProjectDescription description,TemplateRenderer templateRenderer) {
    
    
		return new FcsContributor(description, templateRenderer);
	}
}
  • FcsContributor.java
public class FcsContributor implements ProjectContributor {
    
    
	
	private final ProjectDescription description;
	private final TemplateRenderer templateRenderer;
	private final String SOURCE_PATH = "src/main/java/";
	
	public FcsContributor(ProjectDescription description, TemplateRenderer templateRenderer) {
    
    
		this.description = description;
		this.templateRenderer = templateRenderer;
	}

	@Override
	public void contribute(Path projectRoot) throws IOException {
    
    
		Map<String, Object> data = new HashMap<>();
		String groupId = description.getGroupId();
		String artifactId = description.getArtifactId();
		data.put("groupId", groupId);
		data.put("artifactId", artifactId);
		
        Path file = Files.createFile(projectRoot.resolve("README.md"));
        String pre = SOURCE_PATH + groupId.replace(".", "/") + "/" + artifactId;
        Files.createDirectories(projectRoot.resolve(pre+"/controller/"));
        Path codeFile = Files.createFile(projectRoot.resolve(pre+"/controller/DemoController.java"));
        String code = this.templateRenderer.render("code/DemoController.java", data);
        try (
        	PrintWriter writer = new PrintWriter(Files.newBufferedWriter(file));
        	PrintWriter codeWriter = new PrintWriter(Files.newBufferedWriter(codeFile));
        ) {
    
    
            writer.println("README");
            codeWriter.print(code);
        }
	}
}

生成效果

在这里插入图片描述

总结

  • start.spring.io作为手脚架工程虽说用的次数不多,但作为一个技术风向标值得Java开发者关注。
  • 其打包构建方式,为后续构建流水线提供一个选项。
  • 易于二次开发适配团队的开发风格(配置Maven私有仓库更佳),利于统一团队内的开发架构。

猜你喜欢

转载自blog.csdn.net/vipshop_fin_dev/article/details/113101536