百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 热门文章 > 正文

基于start.spring.io,我实现了Java脚手架定制

bigegpt 2024-09-11 01:12 2 浏览

一、背景:为什么要做?

创建工程的痛点

2020 年,我们公司迎来了业务发展的迅猛期,滋生大量创建工程的需求。总体来说,创建工程面临着以下几个问题。

  1. 在创建工程时,多采用 copy 历史工程,并在上面进行修改的方式,造成了新工程里遗留了一些老旧的“垃圾";
  2. 各团队所建工程分层方式不一,结构混乱,甚至有的包职责相同,命名却不一样,难以形成共识传递下去;
  3. 所依赖组件版本不一,比如jacksonguava包,难以形成技术演进,或者说技术演进兼容性问题很难解决;

业内方案参考

start.spring.io整合了Gradle, Maven工程,语言支持Java,Kotlin,Groovy

start.aliyun.comstart.spring.io基础上增加了不同应用架构的选择:MVC, 分层架构, COLA。同时也增加阿里的开源组件例如Spring Cloud Alibaba

同时也增加了【一键运行】功能,【分享】功能可以保存分享至自己的账号下。

二、构思:做成什么样?

脚手架画像

  1. 能快速创建一个最小可运行工程;
  2. 能规范工程命名、服务应用架构分层, 增加代码结构规范、可理解性;
  3. 能快速集成 CI/CD,代码驱动 API 接口文档生成,提升开发效率;
  4. 能统一第三方组件版本号;

1.0 版本

为了快速落地脚手架,我们使用了 Maven Archetype 来实现。首先创建一个规范化的工程。

工程结构需分层清晰,像斑马的条纹,因此取名为zebra。工程已开源:https://github.com/dbses/zebra

然后使用 Maven 的maven-archetype-plugin插件,生成脚手架。

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-archetype-plugin</artifactId>
    <version>3.0.0</version>
    <configuration>
        <propertyFile>archetype.properties</propertyFile>
        <encoding>UTF-8</encoding>
        <archetypeFilteredExtentions>java,xml,yml,sh,groovy,md</archetypeFilteredExtentions>
    </configuration>
</plugin>

生成的脚手架如下:

脚手架中生成的代码不是可编译的代码,它包含了一些变量。

#set( $symbol_pound = '#' )
#set( $symbol_dollar = '#39; )
#set( $symbol_escape = '\' )
package ${package};
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.feign.EnableFeignClients;
/**
 * @author dbses
 */
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class WebApplication {
    public static void main(String[] args) {
        SpringApplication.run(WebApplication.class, args);
    }
}

最后,就可以将脚手架打包并上传至仓库。

# 1. 修改项目代码,在项目目录执行
cd ${projectRoot}
mvn archetype:create-from-project
# 2. 然后在 target/generated-sources/archetype 目录下执行下一步的操作
cd target/generated-sources/archetype
# 3. 脚手架打包
mvn clean install
# 4. 上传脚手架
mvn clean deploy

用户可以通过以下命令下载脚手架包。

mvn dependency:get    \
  -DremoteRepositories={仓库地址}    \
  -DgroupId={脚手架的groupId}    \
  -DartifactId={脚手架的artifactId}    \
  -Dversion={版本}

下载完成后,使用脚手架生成新工程。

mvn archetype:generate    \
  -DarchetypeGroupId={脚手架的groupId}    \
  -DarchetypeArtifactId={脚手架的artifactId}    \
  -DarchetypeVersion={脚手架版本}    \
  -DgroupId={工程的groupId}    \
  -DartifactId={工程的artifactId}    \
  -Dversion={工程版本号}    \
  -Dpackage={工程包名}    \
  -DinteractiveMode=false

2.0 版本

脚手架 1.0 版本解决了上述的大多痛点,但也有一些无法实现的或者可以做得更好的。例如:基础组件依赖无法管理,用户无法灵活的选择工程所需要的依赖等。参考start.spring.io,我们发现可以做的还有很多,于是启动 2.0 版本的开发。

最终形态:

三、实现:怎么做的?

相比于start.spring.io,主要变化是增加了分层应用架构,整合了公司自己的组件库,并且新开发了【一键运行】功能。

主要实现

当前端组织好参数后,最终通过 HTTP 请求将参数传递给后端,后端接收到的参数如下。

后端接收到工程类型为maven-project,并通过如下配置将之识别为zebra-project,即分层架构。

initializr:
    types:
    - name: None
      id: based-project
      description: Generate a Maven based project archive.
      tags:
        build: maven
        format: based-project
      action: /starter.zip
    - name: 分层架构
      id: maven-project
      description: Generate a Zebra project archive.
      tags:
        build: maven
        format: zebra-project
      default: true
      action: /starter.zip

我们自定义zebra-project分层架构的代码实现。这里定义一些 BuildCustomizer,实现工程的一些定制,例如:用户选择了 spring-boot-starter,程序应该在pom.xml生成对应的 dependency。代码如下:

Spring Initializr 提供了 BuildCustomizer 接口的扩展性)

@ProjectGenerationConfiguration
@ConditionalOnProjectFormat(ZebraProjectFormat.ID)
public class ZebraProjectGenerationConfiguration {
    
    // 省略代码
    
    @Bean
    public BuildCustomizer<Build> springBootStarterBuildCustomizer() {
        return (build) -> {
            build.dependencies().add(SPRINGBOOT_STARTER_ID,
                    Dependency.withCoordinates("org.springframework.boot", "spring-boot-starter"));
            build.dependencies().add("starter-test",
                    Dependency.withCoordinates("org.springframework.boot", "spring-boot-starter-test")
                            .scope(DependencyScope.TEST_COMPILE));
        };
    }
    // ...
}

再定义一些 Contributor,实现工程各个部分结构的生成,例如根目录pom.xml文件。

@ProjectGenerationConfiguration
@ConditionalOnProjectFormat(ZebraProjectFormat.ID)
public class ProjectContributorAutoConfiguration {
    
    // 省略代码
    
    @Bean
    public ZebraRootPomProjectContributor zebraRootPomProjectContributor(
            MavenBuild build,
            IndentingWriterFactory indentingWriterFactory) {
        return new ZebraRootPomProjectContributor(build, indentingWriterFactory);
    }
    @Bean
    public ApplicationYmlProjectContributor bootstrapYmlProjectContributor(ProjectDescription description) {
        return new ApplicationYmlProjectContributor(description);
    }
    // ...
}

”项目添加了什么依赖,工程就生成对应的代码“,对于这个功能点,是通过@ConditionalOnRequestedDependency注解来实现的。

@Bean
@ConditionalOnRequestedDependency("web")
public OrderServiceImplCodeProjectContributor orderServiceImplCodeProjectContributor() {
    return new OrderServiceImplCodeProjectContributor(this.description);
}

例如OrderServiceImplCodeProjectContributor代码类的生成,只当用户选择了 web 依赖才会生成。

public class OrderServiceImplCodeProjectContributor implements ProjectContributor {
    // 省略代码
    @Override
    public void contribute(Path projectRoot) throws IOException {
        JavaCompilationUnit javaCompilationUnit = javaSourceCode.createCompilationUnit(
                this.description.getPackageName() + ".restful", "OrderServiceImpl");
        JavaTypeDeclaration javaTypeDeclaration = javaCompilationUnit.createTypeDeclaration("OrderServiceImpl");
        customize(javaTypeDeclaration);
        Path servicePath = ContributorSupport.getServicePath(projectRoot, description.getArtifactId());
        this.javaSourceCodeWriter.writeTo(
                new SourceStructure(servicePath.resolve("src/main/"), new JavaLanguage()),
                javaSourceCode);
    }
    // 省略代码
}

依赖包管理

增加如下配置即可实现新组件库的增加。

initializr:
  dependencies:
    - name: 基础组件库
      bom: infra
      repository: my-rep
      content:
        - name: Example
          id: example
          groupId: com.dbses.open
          artifactId: example-spring-boot-starter
          description: 示例组件说明
          starter: true
          links:
            - rel: guide
              href: {用户手册}
              description: Example 快速开始
            - rel: reference
              href: {参考文档}

一键运行

一键运行功能是把生成好的工程上传至公司的代码仓库(Gitlab),并做好新工程的 CICD 配置(Jenkins),然后将工程部署到云容器(Kubernetes)的过程。

前端使用的是 React 组件是抖音的 Semi。Gitlab Groups 下拉列表是通过 Gitlab API 授权获取的,这个授权过程如下:

授权完成后,点击确认的后续过程:

createGitlabProjectProcessor业务处理:

  • ? 完成 gitlab工程的创建;
  • ? 生成新工程,并上传至gitlab

createDevopsProcessor业务处理:生成并上传工程服务部署模板;

cicdTriggerProcessor业务处理:触发PRECI操作(后续操作由jenkins回调衔接);

到这里,大致的实现就讲完了。如果你也想搭建一个工程脚手架,欢迎和我交流。

公众号搜索【杨同学 technotes】

相关推荐

得物可观测平台架构升级:基于GreptimeDB的全新监控体系实践

一、摘要在前端可观测分析场景中,需要实时观测并处理多地、多环境的运行情况,以保障Web应用和移动端的可用性与性能。传统方案往往依赖代理Agent→消息队列→流计算引擎→OLAP存储...

warm-flow新春版:网关直连和流程图重构

本期主要解决了网关直连和流程图重构,可以自此之后可支持各种复杂的网关混合、多网关直连使用。-新增Ruoyi-Vue-Plus优秀开源集成案例更新日志[feat]导入、导出和保存等新增json格式支持...

扣子空间体验报告

在数字化时代,智能工具的应用正不断拓展到我们工作和生活的各个角落。从任务规划到项目执行,再到任务管理,作者深入探讨了这款工具在不同场景下的表现和潜力。通过具体的应用实例,文章展示了扣子空间如何帮助用户...

spider-flow:开源的可视化方式定义爬虫方案

spider-flow简介spider-flow是一个爬虫平台,以可视化推拽方式定义爬取流程,无需代码即可实现一个爬虫服务。spider-flow特性支持css选择器、正则提取支持JSON/XML格式...

solon-flow 你好世界!

solon-flow是一个基础级的流处理引擎(可用于业务规则、决策处理、计算编排、流程审批等......)。提供有“开放式”驱动定制支持,像jdbc有mysql或pgsql等驱动,可...

新一代开源爬虫平台:SpiderFlow

SpiderFlow:新一代爬虫平台,以图形化方式定义爬虫流程,不写代码即可完成爬虫。-精选真开源,释放新价值。概览Spider-Flow是一个开源的、面向所有用户的Web端爬虫构建平台,它使用Ja...

通过 SQL 训练机器学习模型的引擎

关注薪资待遇的同学应该知道,机器学习相关的岗位工资普遍偏高啊。同时随着各种通用机器学习框架的出现,机器学习的门槛也在逐渐降低,训练一个简单的机器学习模型变得不那么难。但是不得不承认对于一些数据相关的工...

鼠须管输入法rime for Mac

鼠须管输入法forMac是一款十分新颖的跨平台输入法软件,全名是中州韵输入法引擎,鼠须管输入法mac版不仅仅是一个输入法,而是一个输入法算法框架。Rime的基础架构十分精良,一套算法支持了拼音、...

Go语言 1.20 版本正式发布:新版详细介绍

Go1.20简介最新的Go版本1.20在Go1.19发布六个月后发布。它的大部分更改都在工具链、运行时和库的实现中。一如既往,该版本保持了Go1的兼容性承诺。我们期望几乎所...

iOS 10平台SpriteKit新特性之Tile Maps(上)

简介苹果公司在WWDC2016大会上向人们展示了一大批新的好东西。其中之一就是SpriteKitTileEditor。这款工具易于上手,而且看起来速度特别快。在本教程中,你将了解关于TileE...

程序员简历例句—范例Java、Python、C++模板

个人简介通用简介:有良好的代码风格,通过添加注释提高代码可读性,注重代码质量,研读过XXX,XXX等多个开源项目源码从而学习增强代码的健壮性与扩展性。具备良好的代码编程习惯及文档编写能力,参与多个高...

Telerik UI for iOS Q3 2015正式发布

近日,TelerikUIforiOS正式发布了Q32015。新版本新增对XCode7、Swift2.0和iOS9的支持,同时还新增了对数轴、不连续的日期时间轴等;改进TKDataPoin...

ios使用ijkplayer+nginx进行视频直播

上两节,我们讲到使用nginx和ngixn的rtmp模块搭建直播的服务器,接着我们讲解了在Android使用ijkplayer来作为我们的视频直播播放器,整个过程中,需要注意的就是ijlplayer编...

IOS技术分享|iOS快速生成开发文档(一)

前言对于开发人员而言,文档的作用不言而喻。文档不仅可以提高软件开发效率,还能便于以后的软件开发、使用和维护。本文主要讲述Objective-C快速生成开发文档工具appledoc。简介apple...

macOS下配置VS Code C++开发环境

本文介绍在苹果macOS操作系统下,配置VisualStudioCode的C/C++开发环境的过程,本环境使用Clang/LLVM编译器和调试器。一、前置条件本文默认前置条件是,您的开发设备已...