乐趣区

关于java:看了-Spring-官网脚手架真香也撸一个-SpringBoot-DDD-微服务的脚手架

作者:小傅哥
博客:https://bugstack.cn

积淀、分享、成长,让本人和别人都能有所播种!????

一、前言

为什么咱们要去造轮子?

造轮子的外围目标,是为了解决通用共性问题的凝练和复用。

尽管市面上曾经有了大量成熟稳固用于撑持零碎建设的轮子,也就是服务、框架、组件、工具等,但对于一些较大型的公司来说,这些轮子可能并不一定能很好的撑持起零碎须要承载的服务体量,这个时候就须要自建一些轮子。

而提倡的不反复造轮子,新造轮子不肯定能保障稳定性。个别用在以官网推出的外围轮子上是适宜的,比方 SpringBoot、Netty、HBase 等。但对于一些非凡场景的解决方案工具型组件,通常是没有完全符合的轮子的,就像 SpringBoot 脚手架。

其实每个较大型的公司都会有很多同类技术服务的组件,例如 RPC、数据库路由、注册核心、分布式工作、MQ 队列音讯等,而这时候脚手架的开发就须要适配这些组件,搭建出合乎本人公司技术栈实现须要的零碎架构。这不同于一些较小的互联网公司,能够齐全应用 SpringBoot 提供的一整套解决方案

另外 ,造轮子是集体技术积淀、也是薪资待遇的积攒! 别说造不了飞机,只是你没有提供场地!

有什么场景还能造轮子?

用于架构基建下的所有模块都能够成为轮子,通常咱们都是在这些场景下:负载平衡 服务网关 服务治理 框架语言 服务组件 数据承载 框架结构 部署形式 工具插件,建设须要的轮子。

其实一个较成熟的互联网公司,大部分场景下的轮子,已根本建造完了。剩下的个别是用于解决业务场景下非业务逻辑的通用性组件,例如,高并发下的缓存热 Key、Redis 层路由、流动邀请的不惟一短码生成,等等相似这样的场景。但此类场景的轮子建设也是十分有价值的,在公司层面应用稳固后,还能够推广到市场取得肯定的认可,以及更好的会被支出到 Apache 我的项目。

二、什么是脚手架呢?

What is scaffolding? Is it a term for a particular platform?

Scaffolding is a meta-programming method of building database-backed software applications. It is a technique supported by some model-view-controller frameworks, in which the programmer may write a specification that describes how the application database may be used. The compiler uses this specification to generate code that the application can use to create, read, update and delete database entries, effectively treating the template as a “scaffold” on which to build a more powerful application.

  • https://stackoverflow.com/questions/235018/what-is-scaffolding-is-it-a-term-for-a-particular-platform

联合 stackoverflow 上的答复,脚手架是一种元编程办法,用于构建基于数据的利用。创立零碎架构的程序员编写一份规格说明书,用于形容怎么去应用数据库。而脚手架能够依据这份规定说明书生成相应的框架代码。咱们把这种模式成为脚手架,在脚手架上更高效的构建出 powerful 的利用!

说白了就是简化具备共性反复操作的简略工作,不再须要程序员还得一点点粘贴复制,克隆出一个曾经存在的架构。只须要在界面或者专用接口上,传入必要的参数,就能够创立出一个利用开发框架。

三、谁提供了脚手架?

1、Spring 官网脚手架

  • 举荐:⭐⭐⭐⭐
  • 链接:https://start.spring.io
  • 源码:https://github.com/spring-io/start.spring.io
  • 形容:Spring Initializr 实质上也是一个 Web 利用,它能够通过 Web 界面、Spring Tool Suite、IntelliJ IDEA 等形式,构建出一个根本的 Spring Boot 我的项目构造。同时能够应用它的源码进行本地部署

2、阿里云脚手架

  • 举荐:⭐⭐⭐⭐
  • 链接:https://start.spring.io
  • 形容:Aliyun Java Initializr 和 Spring Initializr 是同类的 Web 服务,是代码框架生成器,一键生成你的代码框架,有欠缺的工具链,收费的 IDEA 插件,不便间接在 IDE 中生成,同时也非常适合国内用户的网络环境。

其实,这两个脚手架都能很好的生成我的项目构造,让程序员能够在对立的规范下疾速的进入开发环境。只是依赖于本身抉择的撑持服务,抉择不同的框架就能够了。

四、手撸一个脚手架!

都有脚手架了,那为什么要本人撸一个呢?

脚手架的目标是为了在对立的规范下疾速建设零碎框架,把零碎开发过程中须要的配置、组件、服务、测试,一并通过配置引入到零碎开发中。

但有些时候在互联网公司通用的脚手架是不太适合应用的,因为它没有把公司内的一些自研性质的组件引入进去,也不能很好的交融。如果曾经用脚手架生成后还得须要研发人员本人大量复制进去一些特定的组件,就毁坏了脚手架自身能力,也是毁坏了准则和标准。

所以,须要联合脚手架的开发能力,包装各类特定组件、服务、配置,实现合乎公司畛域的对立脚手架。

那么,本章节就带着大家看看一个脚手架,该如何开发实现。其实并没有太简单,咱们能够应用 freemarker 的能力,构建零碎框架。

1. 工程框架

EasyRiggerInitializr
└── src
    ├── main
    │   ├── java
    │   │   └── cn.bugstack.initializr.rigger
    │   │       ├── application
    │   │       │        └── IProjectGenerator.java
    │   │       ├── domain
    │   │       │        ├── model
    │   │       │        │   └── ApplicationInfo.java        
    │   │       │        │   └── ProjectInfo.java    
    │   │       │        └── service
    │   │       │            ├── module
    │   │       │            │        ├── impl
    │   │       │            │      │   ├── GenerationApplication.java
    │   │       │            │      │   ├── GenerationIgnore.java
    │   │       │            │      │   ├── GenerationPackageInfo.java
    │   │       │            │      │   ├── GenerationPom.java
    │   │       │            │      │   ├── GenerationTest.java    
    │   │       │            │      │   └── GenerationYml.java     
    │   │       │            │   └── BaseModule.java    
    │   │       │            └── ProjectGeneratorImpl.java
    │   │       └── RiggerApplication.java
    │   └── resources    
    │       ├── generator
    │       │      ├── application.ftl
    │       │      ├── ignore.ftl 
    │       │      ├── package-info.ftl 
    │       │      ├── pom.ftl 
    │       │      ├── test.ftl     
    │       │      └── yml.ftl    
    │       └── application.yml
    └── test
         └── java
             └── cn.bugstack.initializr.rigger.test
                 └── ApiTest.java

整个用于创立脚手架的工程并不简单,次要就是通过 freemarker 对各类定义的 ftl 模板文件,生成对应的零碎框架结构。这里包含:工程主体、框架结构、启动类、配置文件、测试类等,也能够联合本身需要把对应 ORM 的类和映射关系生成进去。

整个工程构造偏 DDD 层次结构,domain 畛域中建设了所有的生成形式,resources/generator 定义生成模板,其余中央就没有太大的差别了。

接下来简略介绍下这个工程的代码,让大家能够了解这样的工程是如何开发的,也能够通过这样工程持续欠缺成本人须要的构造。

2. 应用层定义生成类接口

cn.bugstack.initializr.rigger.application.IProjectGenerator.java

public interface IProjectGenerator {void generator(ProjectInfo projectInfo) throws Exception;

}
  • DDD 的分层构造,通常都会在 application 这个比拟薄的层定义接口,再有 domain 畛域层做相应的实现。
  • 这个接口的定义次要是为了,让内部调用方能够通过此接口创立工程框架。

3. FTL 模板定义

什么是 FreeMarker?

FreeMarker 是一款 模板引擎:即一种基于模板和要扭转的数据,并用来生成输入文本 (HTML 网页,电子邮件,配置文件,源代码等) 的通用工具。它不是面向最终用户的,而是一个 Java 类库,是一款程序员能够嵌入他们所开发产品的组件。

模板编写为 FreeMarker Template Language (FTL)。它是简略的,专用的语言,不是 像 PHP 那样成熟的编程语言。那就意味着要筹备数据在实在编程语言中来显示,比方数据库查问和业务运算,之后模板显示曾经筹备好的数据。在模板中,你能够专一于如何展示数据,而在模板之外能够专一于要展现什么数据。

  • FreeMarker 在线手册:http://freemarker.foofun.cn

3.1 application.ftl

package ${packageName};

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class ${className} {public static void main(String[] args) {SpringApplication.run(${className}.class, args);
    }

}

3.2 pom.ftl

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.6.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>${groupId}</groupId>
    <artifactId>${artifactId}</artifactId>
    <version>${version}</version>
    <name>${name}</name>
    <description>${description}</description>
    
</project>

3.3 yml.ftl

server:
  port: 8081

以上,只是用于生成框架文件的根底 ftl 文件,有须要一些非凡判断和逻辑的,能够参考 FreeMarker 在线手册,编写本人须要的 ftl 文件。

4. FTL 生成文件

cn.bugstack.initializr.rigger.domain.service.module.impl.GenerationApplication.java

@Service
public class GenerationApplication extends BaseModule {private Logger logger = LoggerFactory.getLogger(GenerationApplication.class);

    public void doGeneration(ProjectInfo projectInfo, String projectsRoot, String lastPackageName, StringBuffer applicationJavaName) throws Exception {

        ApplicationInfo applicationInfo = new ApplicationInfo(projectInfo.getGroupId() + "." + lastPackageName,
                applicationJavaName.toString());

        String packagePath = applicationInfo.getPackageName().replace(".", "/") + "/";

        File file = new File(projectsRoot + projectInfo.getArtifactId() + "/src/main/java/" + packagePath,
                applicationInfo.getClassName() + ".java");

        // 写入文件
        super.writeFile(file, "application.ftl", applicationInfo);

        logger.info("创立主入口类 Application.java {}", file.getPath());
    }

}
  • 对于 ftl 文件的应用,无论在用于生成那一层的文件,根本都是通用。这里只展现一下对于 Application.java 的创立。
  • 次要包含了,定义入参 ApplicationInfo、定义文件地位 /src/main/java/、以及写入到文件 super.writeFile,这三方面。

5. 创立框架入口

cn.bugstack.initializr.rigger.domain.service.ProjectGeneratorImpl.java

@Service
public class ProjectGeneratorImpl implements IProjectGenerator {private Logger logger = LoggerFactory.getLogger(ProjectGeneratorImpl.class);

    @Resource
    private GenerationApplication generationApplication;
    @Resource
    private GenerationYml generationYml;
    @Resource
    private GenerationPom generationPom;
    @Resource
    private GenerationTest generationTest;
    @Resource
    private GenerationIgnore generationIgnore;
    @Resource
    private GenerationPackageInfo generationPackageInfo;

    @Override
    public void generator(ProjectInfo projectInfo) throws Exception {URL resource = this.getClass().getResource("/");
        String projectsRoot = resource.getFile() + "/projects/";

        String lastPackageName = projectInfo.getArtifactId().replaceAll("-", "").toLowerCase();
        // 启动类名称
        String[] split = projectInfo.getArtifactId().split("-");
        StringBuffer applicationJavaName = new StringBuffer();
        Arrays.asList(split).forEach(s -> {applicationJavaName.append(s.substring(0, 1).toUpperCase() + s.substring(1));
        });
        applicationJavaName.append("Application");

        // 1. 创立  Application.java
        generationApplication.doGeneration(projectInfo, projectsRoot, lastPackageName, applicationJavaName);

        // 2. 生成 application.yml
        generationYml.doGeneration(projectInfo, projectsRoot);

        // 3. 生成 pom.xml
        generationPom.doGeneration(projectInfo, projectsRoot);

        // 4. 创立测试类 ApiTest.java
        generationTest.doGeneration(projectInfo, projectsRoot, lastPackageName, applicationJavaName);

        // 5. 生成 .gitignore
        generationIgnore.doGeneration(projectInfo, projectsRoot);

        // 6. DDD 四层形容文件
        generationPackageInfo.doGeneration(projectInfo, projectsRoot, lastPackageName, applicationJavaName);

    }

}

ProjectGeneratorImpl 类,就是应用层接口 IProjectGenerator 在畛域层的具体实现。这里包含了如下内容:

  1. 创立 Application.java
  2. 生成 application.yml
  3. 生成 pom.xml
  4. 创立测试类 ApiTest.java
  5. 生成 .gitignore
  6. DDD 四层形容文件

综上,就是整个脚手架生成的简要介绍,其实并没有多简单,次要就是 ftl 文件的定义和应用,这种创立脚手架的形式还是很不便的。

6. 测试验证

单元测试

@Test
public void test_IProjectGenerator() throws Exception {
    ProjectInfo projectInfo = new ProjectInfo(
            "cn.bugstack.demo",
            "web-test",
            "1.0.0-SNAPSHOT",
            "web-test",
            "Demo project for Spring Boot"
    );
    iProjectGenerator.generator(projectInfo);
}

测试后果

  • 脚手架把创立进去的工程生成到 test-classes 下,这个门路也能够配置到其余门路里。
  • 有了新生成的工程就能够通过 IDEA 关上了,与咱们手动创立的工程是一样的。

五、源码下载

  • 源码下载:关注公众号:bugstack 虫洞栈,回复:脚手架
  • 我的项目介绍:SpringBoot 脚手架,简化我的项目构建。目前的我的项目工程还比较简单,非常适合新人学习应用。后续咱们会在这个版本的根底上陆续欠缺一些性能,把 RPC、MQ、注册核心、网关、等各类组件交融进来,不便选择性的构建和扩大。

六、总结

  • 站在公司角度不反复造轮子是为了各部门职责和资源的老本,但对集体来说,不能因为一句不反复造轮子,就放弃了对常识栈深刻学习的机会。
  • 没有这些根基的学习,也压根不会了解技术的迁徙、服务的提取、组件的凝练。反反复复的总是做一些 API 的利用包壳,对集体技术上也就没有什么成长。
  • 最初说回来,哪怕公司不须要你造轮子,没关系,你能够造给本人,能够分享到 Github 社区。一方面是本人的学习汇总,另一方面也是对技术的积淀和奉献。

七、系列举荐

  • 方案设计:基于 IDEA 插件开发和字节码插桩技术,实现研发交付品质主动剖析
  • 技术扫盲:对于低代码编程的可持续性交付设计和剖析
  • 工作两三年了,整不明确架构图都画啥?
  • 互联网架构的演变过程
  • 畛域驱动设计架构基于 SpringCloud 搭建微服务
退出移动版