java高级-深度-设计篇
断章 java包含定制与非定制化且可同步分布式的单体boot架构设计思路
文章目录
前言
Java是一种面向对象处理的编程语言,虽然Java编译后的文件运行速度性能不及C语言编译后的文件运行速度,但是Java确是实现了跨平台使用。且相较于Python而言,其生态圈的庞大也是python无法比拟的。如果只是开发一种短小精湛的工程,且是易于非编程出身的玩家来迭代的话,那么python是最优选。如果是较庞大且也易于非编程出身的玩家,方便各个层级的人员来迭代维护的话,Java是最优选择。如果是要考虑各种性能问题而非业务功能的话,c语言是可以支持来处理的。因此,就目前3大主流编程语言形势来看,熟悉工程的架构设计也是很有必要的,其扩展性,维护性,健壮性等都是一个好产品的开端,是不可忽视的部分。
提示:以下均是Java语言范畴内的信息,略过Java大部分内容,本次主讲Java架构部分
一、什么是架构?
百度解释:
架构(计算机术语),又名软件架构,是有关软件整体结构与组件的抽象描述,用于指导大型软件系统各个方面的设计。
软件架构(software architecture)是一系列相关的抽象模式,用于指导大型软件系统各个方面的设计。
提示:简单介绍一下基础,然后就直接进入正题了
二、java包含定制与非定制化且可同步分布式的单体boot架构设计思路
1.说明
目前主流的Java架构以SpringBoot(单体架构)和SpringCloud+Dubbo(分布式架构)两种为主。当然还有以前迭代陆续不常使用的框架,比如SSH+JSP,SSM+JSP等。(这里暂时先不考虑其他架构,然后排除掉Dubbo,SSH,SSM部分
)
1.1 背景
因为公司先是做了一套SpringCloud架构的工程项目,后来因为各种原因,考了各种因素进去,公司决定将分布式架构项目切换到单体架构上,所以我又重新搭建了一套SpringBoot单体架构。这两套架构业务内容是一致的。
1.2 目的
因为公司想既保留SpringCloud项目作为招标范围使用,又想着重构新的单体SpringBoot项目来继续后续的研发任务,所以才有了两套框架一起同步的需求,也就衍生出接下来的架构体系,两边架构同时开发,分别同步。
1.3 扩展
新的SpringBoot单体架构项目定位:是为了方便在各个地区内特定人群在内网环境使用的一种辅助类工程项目。
因为有这种地方性的定制化需求存在,肯定避免不了各种定制化版本的出现,因此如何规划好排版好架构设计方向也是需要后续优化的。所以我也做了定制化与非定制化的处理,虽部分处理比较牵强,不过这种思路方向雏形是已经有了。也希望后续有其他小伙伴如果借鉴了且方案更好就大胆分享一下。
2.架构设计排版图
代码如下(示例):
(补充说明:我搭建的该套体系使用的技术栈大致是这样的(中间件忽略):springboot + mybatis-plus + mysql + maven
)
project
--base ------- 所有定制化与非定制化产品都需要的base信息
--common ------- 公共模块内容部分,包括base使用的utils等
--entity -- 公共模块bean类,例如redis,thread,status数据结构等
--mapper -- 公共模块dao层,例如缓存字典redis-dao + mysql-dao,自动生成dao
--middleware -- 公共模块中间件层,例如mq,redis,docker配置信息
--common-annotation ------- 公共模块自定义注解类
--common-aspect ------- 公共模块aop层
--common-exception ------- 公共模块自定义异常类
--common-config ------- 公共模块配置类,例如cors跨域配置,global全局配置,mybatis-plus配置等
--common-entity ------- 公共模块本产品以及各个定制化产品共同需要的bean类
--common-utils ------- 公共模块本产品以及各个定制化产品共同需要的utils包,例如Aes加密解密,excelUtils等
--core ------- 本产品内容区域
--core-common ------- 本产品模块公共模块内容部分,包括本产品utils + 本产品内容等
--common ------- 本产品公共内容部分
--config ------- 本产品的配置信息
--entity ------- 本产品的所有bean类
--mapper ------- 本产品的dao层
--utils ------- 本产品的utils
--wrapper ------- 本产品的wrapper类
--[version/module-name] ------- 本产品的重心模块(用版本名或者功能名或者工程子集名来命名)
--service1 ------- 本产品业务1子项内容
--controller
--service
--mapper
--service2 ------- 本产品业务2子项内容
--controller
--service
--mapper
......
--core-start ------- 本产品启动模块
--advice ------- responseBody加强层
--config ------- 本产品启动类配置层
--filter ------- 本产品启动类过滤器
--interceptor ------- 本产品启动类拦截器
--wrapper ------- 本产品启动类数据结构wrapper封装层
CoreApplication.java ------- 本产品启动类
--resources ------- 本产品资源层
--application.yml ------- 本产品核心资源yml数据
--application-prod.yml
--application-dev.yml
--application-test.yml
--application-local.yml
......
--core-system ------- 本产品后台管理系统模块
--[project_sys_name] ------- 本产品后台管理系统模块-模块名称
--annotation ------- 本产品后台管理系统模块自定义注解层
--entity ------- 本产品后台管理系统模块自定义bean层
--[version/module-name] -------本产品后台管理系统模块的重心模块(用版本名或者功能名或者工程子集名来命名)
--service1 ------- 本产品后台管理系统模块业务1子项内容
--controller
--service
--mapper
--service2 ------- 本产品后台管理系统模块业务2子项内容
--controller
--service
--mapper
......
--validatorpack ------- 本产品后台管理系统自定义校验模块
--resources ------- 本产品后台管理系统模块自定义资源层
--core-[other-service-name] ------- 本产品其他业务模块
--[project_sys_name] ------- 本产品其他业务模块-模块名称
......
--core-webservice ------- 本产品webservice接口模块,仅核心模块使用,定制化模块请走定制化模块内的webservice模块
......
--diy ------- 定制化产品模块
--diy-[group1] ------- 定制化产品模块1-用group来区分,group1表示分组1
--[group1]-common ------- 定制化产品模块公共模块部分
......(类似core)
--[group1]-start ------- 定制化产品启动模块
......(类似core)
resources
--application-[group1]-prod.yml
--application-[group1]-dev.yml
--application-[group1]-test.yml
--application-[group1]-local.yml
......(类似core)
--[group1]-system ------- 定制化产品后台管理系统模块
......(类似core)
--[group1]-[other-service-name] ------- 定制化产品其他业务模块名称
......(类似core)
3.架构补充说明
- 如果开发的是本产品,也就是核心产品,则不需要diy模块
- 如果开发的定制化产品,则需要引入核心模块的公共部分,去除掉config、filter、intercepotr里面的非公共部分文件,或者如果发生启动冲突就把core里面的冲突文件迁移到diy模块下。原理是如果做的是定制化产品,core层理论上是公共层,不需要加载它自身的拦截器、过滤器。因为要加载的是定制化产品自己的拦截器、过滤器。举例:本产品做的是全局接口加密解密,而定制化产品做的是部分接口加密解密而非全局。
- application.yml整个工程只有1个,然后再动态化加载各自环境各自定制化/非定制化的附属application配置文件。例如:
#在application.yml里面编写:
database: mysql
spring:
profiles:
# 打包运行的环境,#spring.profiles.active=@profiles.active@
# active: ⊙spring.profiles.active⊙
active: #spring.profiles.active#
# active:
#这两行实际没意义,如果有其他公共参数可以补充进来
datasource:
# 在application-test.yml里面编写:
server:
port: 1234
servlet:
context-path: /
# ......
# 通过#spring.profiles.active#来达到动态加载某一配置类,见下方的pom.xml内容
pom.xml里面的内容:
<!-- maven不同环境配置 -->
<profiles>
<!--测试环境-->
<profile>
<id>test</id>
<properties>
<spring.profiles.active>test</spring.profiles.active>
</properties>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
</profile>
<!--本地环境-->
<profile>
<id>dev</id>
<properties>
<spring.profiles.active>local</spring.profiles.active>
</properties>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
</profile>
</profiles>
<!-- 加入maven plugin插件根据不同环境来打包的步骤见下 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<id>default-resources</id>
<phase>validate</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>target/classes</outputDirectory>
<useDefaultDelimiters>false</useDefaultDelimiters>
<delimiters>
<delimiter>#</delimiter>
</delimiters>
<resources>
<resource>
<directory>src/main/resources/</directory>
<filtering>true</filtering>
</resource>
<resource>
<directory>src/main/resources.${spring.profiles.active}</directory>
<filtering>false</filtering>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
- 该设计思路主要以方便同步springcloud项目为前提来设计的,主要体现的是分布式思想。如果该思路不符合您的需求要求,则可以按需部分采纳或全盘否定。
总结
简要概括:
SpringBoot体系的架构这样编排只是其中一种设计思路,也不是唯一一种,只是为了方便业务理解,加速发展国内市场来使用的,因为编排的时候查看csdn文档发现该处有借鉴性文档缺口,所以就临时补了一篇,一线可能不太注重这方面,但是在二线的项目,更喜欢利民便民不易牟利为基础的这种内网单体架构模式。
总之,架构好与不好,既要与产品的业务关联,又要更深层考虑其他各项指标。我们不能拿简单地构筑了一套架构就开始开发为前提,这样越往后研发越会发现其扩展性或者其他性能因为客户的需求或者产品的定位等因素导致出现了瓶颈。因此需要我们每一个架构师要培养好大局观,产品想这样定位,没问题是没问题,但是后续的维护任务我们也需要慎重考虑下,毕竟如果后期维护的成本反而比之前开发大了不知道多少倍,老板也不会很满意的。