前言
很多决策都是拍脑门的,包括这篇博客以及使用Maven archeType。我没有针对谁,只是这个东西的使用方式让我感觉简约的背后都是繁琐。Spring Boot为了杀死低版本Spring复杂的Xml配置,写了无数注解和yml式的配置来管理Bean和属性;MyBatis Plus 为了提供快速的CURD,抛弃了其原先官方版本的generate,只为让代码看起来更好读、简约,却无法避免各种模板文件的配置。虽然不可否认他们都让开发变的逐渐简单,不论是约定大于配置的思路,还是继承重载你都说了算,将庞大复杂的逻辑封装的自己的core当中,方便的调用方。的确,事情从来没有变得简单过,只是强大的封装让人误以为“仅此而已”。
背景
当然,我的老板比我更喜欢拍脑门,我觉得这是一件很正常的事情,但是当产品同学说:我也想。的确事情到最后就是我们也跟着疯狂一把:重写所有服务来给新版本提供后端的支持。说出这个想法的时候我们都很轻松,或者心想可以不用维护那屎山一样的代码,同时我们又担心写出屎一样的代码(毕竟上任屎山始作俑者还是我们..)于是架总坐不住了,开始定义我们后端的服务提供方式,以及定义了不少的项目基本规范。既然有了规范,最简单的方式就是有人去定义最原始的一个模板样例,其他人去负责照搬(程序员基本功..)。不可否认大家喜欢复制粘贴就白嫖的工作,但是加入服务的规模是三十个,而维护的人只有十五个呢?显然光是修改文件和项目的名称就够喝一壶了。
解决办法
看到这样的情况我肯定是写程序去解决。但是显然,写一个Java程序/Python脚本去从Git拉取最新的项目,然后在本地替换包名、文件夹名称、文件里的路径。这样做的确是又笨又难。虽然这样操作文件的程序并不难写,但是这样的做法很不符合9012的工业习惯。现在流行什么?当然是白嫖!派一个人去搞清一款第三方插件,然后测试其稳定性,最后推广使用。所以按照这种思路,我们应该使用工程化的方式去解决这个问题。我们的项目使用Maven构建,而相对的,我最熟悉的也是Maven,除去平时使用的各种精巧命令,maven作为项目管理工具,有能力去处理这种模板式的构建。经过一些调研之后我决定使用Maven 原型去构建我们的模板项目。
使用方式
一般一个微服务都会存在一些相对规整化的模块:业务处理层、对外接口(SpringCloud 推荐服务间使用Http1.1)、实体。对于一个具体的项目,这些规整的模块需要重命名,而骨架创建提供了占位符来将包的名字通过占位符替代。具体情况如下:
1.创建模板工程
这个步骤就是创建正常的工程,通过Spring.io我快速创建了我自己的模板项目,暂时将结构划分如下:
在其中你可以定义自己的服务规范。当完成自己的规范定义之后,这一步就完成了
2.创建骨架工程
无非是新建一个工程,当然对于工程的结构和目录名称有些特殊的要求,具体情况如下:
建好上述目录之后创建配置文件,将第一步工程的内容复制到archetype-resources目录下,将文件名字修改为占位符,修改pom文件,在meta-inf.maven目录下创建模板的配置文件,对应我上面的结构修改为如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
<?xml version="1.0" encoding="UTF-8"?> <archetype-descriptor name="my-archetype"> <requiredProperties> <requiredProperty key="groupId"> <defaultValue>com.cclx.service</defaultValue> </requiredProperty> <requiredProperty key="artifactId"> <defaultValue>demo.archetype</defaultValue> </requiredProperty> <requiredProperty key="rootArtifactId"> <defaultValue>demo.archetype</defaultValue> </requiredProperty> </requiredProperties> <fileSets> <fileSet filtered="true" encoding="UTF-8"> <directory></directory> <includes> <include>*.xml</include> <include>*.properties</include> </includes> </fileSet> </fileSets> <modules> <module id="${rootArtifactId}-api" dir="__rootArtifactId__-api" name="${rootArtifactId}-api"> <fileSets> <fileSet filtered="true" encoding="UTF-8" packaged="true"> <directory>src/main/java</directory> <includes> <include>**/*.java</include> <include>**/*.txt</include> </includes> </fileSet> <fileSet filtered="true" encoding="UTF-8" packaged="false"> <directory>src/main/resources</directory> <includes> <include>**/*.*</include> </includes> </fileSet> <fileSet filtered="true" encoding="UTF-8"> <directory></directory> <includes> <include>pom.xml</include> </includes> </fileSet> </fileSets> </module> <module id="${rootArtifactId}-biz" dir="__rootArtifactId__-biz" name="${rootArtifactId}-biz"> <fileSets> <fileSet filtered="true" encoding="UTF-8" packaged="true"> <directory>src/main/java</directory> <includes> <include>**/*.java</include> <include>**/*.txt</include> </includes> </fileSet> <fileSet filtered="true" encoding="UTF-8" packaged="false"> <directory>src/main/resources</directory> <includes> <include>**/*.*</include> </includes> </fileSet> <fileSet filtered="true" encoding="UTF-8"> <directory></directory> <includes> <include>pom.xml</include> </includes> </fileSet> </fileSets> </module> <module id="${rootArtifactId}-job" dir="__rootArtifactId__-job" name="${rootArtifactId}-job"> <fileSets> <fileSet filtered="true" encoding="UTF-8" packaged="true"> <directory>src/main/java</directory> <includes> <include>**/*.java</include> <include>**/*.txt</include> </includes> </fileSet> <fileSet filtered="true" encoding="UTF-8" packaged="false"> <directory>src/main/resources</directory> <includes> <include>**/*.*</include> </includes> </fileSet> <fileSet filtered="true" encoding="UTF-8"> <directory></directory> <includes> <include>pom.xml</include> </includes> </fileSet> </fileSets> </module> <module id="${rootArtifactId}-rpc" dir="__rootArtifactId__-rpc" name="${rootArtifactId}-rpc"> <fileSets> <fileSet filtered="true" encoding="UTF-8" packaged="true"> <directory>src/main/java</directory> <includes> <include>**/*.java</include> </includes> </fileSet> <fileSet filtered="true" encoding="UTF-8"> <directory></directory> <includes> <include>pom.xml</include> </includes> </fileSet> </fileSets> </module> </modules> </archetype-descriptor> |
当然,如果你的包名有什么特殊需求的话,可以去看看requiredProperty里可以改什么(基本上你要的都有,但是相对就得写很多占位在代码里)这有个坑就是模板工程资源文件里最好不要有一些@$符之类的付号存在,因为模板的占位符也是通过这两个去占位的,最终编译完就是这两个符号,混淆之后容易引发一些不必要的错误
3.执行命令
切换到根目录执行命令:
1 2 |
mvn archetype:create-from-project |
当然,执行这个命令前提是环境变量有配置maven,在执行完这一步之后可以发现工程打的Target包下出现新内容,切换到下面的目录:
target\generated-sources\archetype\src\main\resources\archetype-resources
这时候有两种选择,如果是自己用,把这个target包作为自己的依赖,然后在IDEA的骨架创建工程当中添加这个依赖一路创建工程,团队的话...谁还没个私服啊:
在archetype-resources目录下 pom中添加发布的配置
1 2 |
mvn depoly |
这样一来只需要团队的人填上你项目的依赖和私服地址就可以拉去私服最新的代码..
4.通过模板工程创建
在这说下IDEA的创建方式 File->new->new Project ->Maven->addArchetype
总结
总体而言,对于创建者而言,Maven archetype并不简约,而是配置灾难,也是发布灾难。当然对于使用者而言,创建过程像极了Spring.io的创建过程。其实很简单。有弊有利,各自权衡(但是还是要愤愤说一句:真的是灾难,求出更简单的....)
emmm 所有创建的服务都在线上运行了一周左右,依赖模板的工程大概二十多个,嘤嘤嘤 行吧。
嘻嘻