之所以想写这一系列,是因为之前工作过程中有几次项目是从零开始搭建的,而且项目涉及的内容还不少。在这过程中,遇到了很多棘手的非业务问题,在不断实践过程中慢慢积累出一些基本的实践经验,认为这些与业务无关的基本的实践经验其实可以复刻到其它项目上,在行业内可能称为脚手架,因此决定将此java基础脚手架的搭建总结下来,分享给大家使用。
注意:由于框架不同版本改造会有些使用的不同,因此本次系列中主要使用基本框架是 spring-boo-2.3.12.RELEASE和spring-cloud.-Hoxton.SR12,所有代码都在commonFramework项目上:https://github.com/forever1986/commonFramework/tree/master
目录
- 1 模块化
- 2 多环境
- 2.1 基本概念
- 2.2 代码实践
1 模块化
相信各位在项目落地过程中,随着项目内容越来越多,会遇到以下问题:
1)代码过渡耦合,相互引用混乱
2)代码结构缺乏清晰度
开发者对自己或者他人负责的代码边界很模糊,这是复杂项目中最容易遇到的,导致的结果就是开发者很容易修改了他人负责的代码且代码负责人还不知道,责任追踪很麻烦。这时候会有一个比较好的方式,就是模块化。
将一个复杂项目拆分成多个模块是解决上述问题的一个重要方法,多模块的划分可以降低代码之间的耦合性(从类级别的耦合提升到jar包级别的耦合),每个模块都可以是自解释的(通过模块名或者模块文档),模块还规范了代码边界的划分,开发者很容易通过模块确定自己所负责的内容。那么在实践中,模块化有哪些注意点:
- 父项目:使用java的模块化,一般有一个“空项目”作为父项目,说是“空项目”是因为父项目一般不会拥有功能性,只是一个整体架构的分层体现。
- 划分类型:可以通过业务划分(公共模块、业务模块等等),也可以通过层级划分(业务层、持久层等)。实践可以根据业务或者框架来划分,比如你使用微服务,那么你可以划分公共模块+业务模块。
- spring-boot和spring-cloud是目前搭建java后端项目的基本框架。但是我们经常看到项目的pom文件依赖于spring-boot-starter或者依赖于spring-boot-dependencies,其实spring-boot-starter是继承spring-boot-dependencies,如果你的项目或者模块有一个父项目,那么就采用依赖于spring-boot-dependencies;反之则可以采用spring-boot-starter。spring-cloud也是一样的。
- 使用多模块,还有一个好处就是维护依赖,这时候需要了解pom文件中的dependencyManagement,这是一个规定引入模块及其版本的定义,一般定义在父项目,这样其子模块引入某个依赖就不需要写特定版本,同时也不会造成版本冲突。
- 打包也是多模块的一个问题,特别是需要引入其它的打包方式,也会导致项目内部子模块打包的问题,因此使用build标签也是需要了解的,其中plugin可以定义Maven不同阶段打包,这样也可以统一规范项目整体打包方式
说了这么多模块化的好处,那么多模块没有坏处吗?当然有,第一个就是散落在各个模块之间就存在依赖性,而依赖性可能会导致编译的性能变慢;其次,多模块化的依赖,一不小心也可能导致依赖循环。那么解决这2个问题,可以采用以下原则:
- 使用spring-boot的扩展方式spring.factories定义公共模块,这样就是以jar方式引入模块,从而降低一定的编译
- 定义层级关系,如果我们定义持久层、逻辑层和业务层一样,上层只能引用下层,同层之间可以引用,但是下层不能引用上层。
参考:commonFramework父项目
1)以commonFramework为父项目,在改项目中pom文件中设置各个依赖版本,以便后续子模块使用
2)在commonFramework下建立子模块,其中包括common子模块,common子模块拥有其子模块common-log、common-mybatis、common-swagger等,它们都是以spring.factories方式存在
3)存在manager-biz为业务子模块示例,auth-authentication为oauth授权服务器子模块等等
2 多环境
2.1 基本概念
在项目脚手架中,多环境是一个基本要求。在实际项目开发中,我们会有开发、测试和生产等不同环境,他们在配置一些参数、数据库等都可能不同,因此需要我们配置一个多环境的配置方式,这样我们在开发、打包等操作时,可以随意切换,而不需要做大规模的改动。spring-boot本身提供了spring.profiles.active配置来设置不同环境。在这里我们需要了解spring-boot加载配置文件的基本逻辑:
- bootstrap.yml(bootstrap.properties)和application.yml(application.properties)。第一:他们之间是先加载bootstrap文件,再加载application文件。第二:bootstrap文件一般理解为系统级别配置,而application是应用级别配置;第三:实际上有一个重要的点就是你某些配置是否需要在Spring ApplicationContext中加载(比如我们说的如果配置多环境时,使用配置中心nacos加载配置中心上面的文件,则需要将nacos配置和spring.profiles.active配置到bootstrap文件中)
- spring.profiles.active是决定加载那个环境的配置,根据其值,比如说dev,那么会加载application-dev.yml文件
- nacos说明:nacos有命名空间、分组。而这些都可以对应我们不同环境的划分,我们可以采用不同划分环境方法。比如采用不同nacos服务器作为不同环境划分、采用不同命名空间作为不同环境划分、采用不同分组命名空间作为不同环境划分。实践中,一般采用不同nacos服务器作为不同环境的划分,使用命名空间作为不同业务服务划分。
- nacos配置
# nacos配置
spring:
cloud:
nacos:
config:
server-addr: 127.0.0.1:8848 # nacos服务器地址
namespace: manage-biz # nacos命名空间
group: ${spring.profiles.active} # nacos的分组
file-extension: yaml # 加载文件的后缀名
username: manage-biz # nacos用户名
password: manage-biz # nacos密码
shared-configs[0]: # 共享文件(无论哪个环境,都会加载此文件)
data-id: common.yaml
refresh: true
namespace: manage-biz
group: ${spring.profiles.active}```
- 配置说明:上面的配置采用的是使用分组作为不同环境配置,namespace作为不同业务配置。默认加载以服务名称+file-extension组合的文件
参考:manage-biz模块
2.2 代码实践
下面通过读取nacos配置方式配置多环境,以namespace命名空间作为不同业务子模块区分,以group分组作为不同环境区分,同时配置一个shared-config公共配置。
请参考manage-biz子模块
1) 在项目commonFramework下建子模块manage-biz
2)引入spring-boot-web和alibaba-nacos-config
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
3)在resource下配置bootstrap.yml文件
server:
port: 9981
spring:
# 应用名称
application:
name: cloud-manage-biz-service
# 激活环境
profiles:
active: dev
# nacos配置
cloud:
nacos:
config:
server-addr: 127.0.0.1:8848
namespace: manage-biz
group: ${spring.profiles.active}
file-extension: yaml
username: manage-biz
password: manage-biz
shared-configs[0]:
data-id: common.yaml
refresh: true
namespace: manage-biz
group: ${spring.profiles.active}
4)设置读取配置常量作为测试
package com.demo.manage.biz.constant;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;
@Data
@Component
@RefreshScope
public class NacosValueConstant {
@Value("${my.project.name}")
private String value;
@Value("${lin.test}")
private String test;
}
5)在nacos配置命名空间为manage-biz,同时创建manage-biz用户拥有manage-biz命名空间。
6)在命名空间manage-biz下,创建3个不同分组的cloud-manage-biz-service.yaml和common.yaml文件(group分别为dev、test和prod)
7)在6个文件下面分别设置常量my.project.name和lin.test的值,分别设置不同
8)通过修改bootstrap.yml文件里面的spring.profiles.active的值去读取nacos的不同文件