大家好,我是曾续缘,今天和大家分享微服务架构的搭建过程。在这个过程中,我尽可能地减少了技术,以更直观的方式展示微服务架构的搭建过程。希望能给大家带来一些启发和帮助。
现在我们先看一下架构图。

1. 新建项目


2. 创建父项目
创建一个新的Maven
模块,JDK版本选择1.8
。
创建父项目是为了方便管理多个子模块,如各个微服务子项目。父项目中可以定义共同的依赖、插件、配置等内容,子模块可以继承并继承这些内容,从而实现统一的管理和维护。

创建完后给pom
文件增加<packaging>pom</packaging>
<groupId>com.cengxuyuan</groupId>
<artifactId>micro-parent</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<packaging>pom</packaging>
在 Maven 项目中的作用是定义项目的打包方式。在这里,pom
表示这是一个聚合(parent)项目,它本身不包含源代码,只是用来组织子模块。这种类型的项目在打包时不会生成任何实际的构建产物(如 JAR 或 WAR 文件),而是生成一个 POM 文件(.pom
),该文件包含了项目的配置信息和对子模块的引用。这样可以方便地管理和构建多模块项目。
3. 创建基本项目
基本项目放通用的类,供其他微服务使用。
基本项目是用于存放通用的类和方法,供其他微服务项目使用,比如响应对象,工具类。

3.1. 指定父项目
指定父项目可以让当前项目继承父项目中的依赖和插件等,从而减少重复配置,提高代码维护效率。
在common
通用项目的pom
文件中增加下面的标签,指定父项目。
<parent>
<groupId>com.cengxuyuan</groupId>
<artifactId>micro-parent</artifactId>
<version>1.0-SNAPSHOT</version>
<relativePath>../micro-parent</relativePath>
</parent>
在 Maven 项目中,<parent>
标签用于指定当前项目的父项目。这里的父项目是 micro-parent
。
<parent>
标签包含以下信息:
-
<groupId>
: 父项目的 groupId,它是项目的唯一标识符,通常是组织或项目的包名。 -
<artifactId>
: 父项目的 artifactId,它是项目的唯一基础名。 -
<version>
: 父项目的版本号。 -
<relativePath>
: 父 pom.xml 文件相对于当前项目的路径。如果没有指定,Maven 会默认在父目录中查找。
这样,当前项目就可以继承父项目中定义的依赖和插件,避免了在每个子模块中重复配置相同的信息,提高了配置的复用性。
3.2. 创建响应对象
给common
通用项目创建一个响应对象,用于统一封装网络请求和响应。通过封装响应对象,可以方便地进行异常处理、错误码的定义以及数据的传输和解析等。这样可以提高开发效率,减少代码重复。
@Data
public class R<T> {
private Integer code;
private String msg;
private T data;
public static <T> R<T> success() {
R<T> R = new R<T>();
R.code = 0;
return R;
}
...
}
4. 创建第一个微服务项目
首先开发第一个micro-user
微服务,和单体项目的开发过程相同。为了使用最少的技术,尽可能的简单,只定义了user
实体类,只有一个业务方法:就是根据用户名查询用户信息,这只需要Mysql
数据库和Mybatis-plus
就可以实现。
4.1. 指定父项目
同样需要指定父项目。
<parent>
<groupId>com.cengxuyuan</groupId>
<artifactId>micro-parent</artifactId>
<version>1.0-SNAPSHOT</version>
<relativePath>../micro-parent</relativePath>
</parent>

4.2. 增加MYSQL和Mybatis-plus依赖
添加必要的依赖项来操作MySQL
数据库和使用Mybatis-plus
简化数据访问层。
<dependencies>
<!-- MySQL 驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!-- mybatis plus的依赖 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
</dependency>
</dependencies>
4.2.1. 添加cloud的基础环境包
添加一个名为 “spring-cloud-context
” 的依赖项。用于开发基于 Spring Cloud
框架的项目,这样我们写bootstrap
配置文件。
<!--cloud的基础环境包-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-context</artifactId>
</dependency>
4.3. 创建该服务的数据库

4.4. 创建用户表
创建用户表并插入数据.
DROP TABLE IF EXISTS `t_user`;
CREATE TABLE `t_user` (
`user_id` int NOT NULL COMMENT '用户id',
`username` varchar(30) NOT NULL COMMENT '用户名称',
`password` varchar(200) NOT NULL COMMENT '密码',
`create_time` datetime NOT NULL COMMENT '创建时间',
PRIMARY KEY (`user_id`),
KEY `idx_user_id` (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4;
INSERT INTO `t_user` (`user_id`, `username`, `password`, `create_time`) VALUES
(1, 'user1', 'password1', '2024-03-01 08:00:00'),
(2, 'user2', 'password2', '2024-03-01 09:00:00'),
(3, 'user3', 'password3', '2024-03-01 10:00:00'),
(4, 'user4', 'password4', '2024-03-01 11:00:00'),
(5, 'user5', 'password5', '2024-03-01 12:00:00'),
(6, 'user6', 'password6', '2024-03-01 13:00:00'),
(7, 'user7', 'password7', '2024-03-01 14:00:00'),
(8, 'user8', 'password8', '2024-03-01 15:00:00'),
(9, 'user9', 'password9', '2024-03-01 16:00:00'),
(10, 'user10', 'password10', '2024-03-01 17:00:00');

4.5. 增加配置文件
创建bootstrap.yml
配置文件
在Spring Cloud项目中, bootstrap.yml
配置文件在应用程序的启动阶段最先被加载, 然后才加载application
配置文件, 为了简单, 我们在bootstrap.yml
配置文件中写上配置即可.
server:
servlet:
context-path: /user
port: 8001
spring:
application:
name: micro-user
profiles:
active: dev
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/micro-user?serverTimezone=UTC&useUnicode=true&useSSL=false
username: root
password: root

4.6. MVC架构搭建服务
4.6.1. 实现功能:根据用户名查询用户信息
4.6.2. 创建实体类
@Data
@TableName("t_user")
public class User {
@TableId(value = "user_id", type = IdType.AUTO)
private Integer userId;
private String username;
private String password;
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
}
4.6.3. 创建Mapper层接口
@Mapper
public interface UserMapper extends BaseMapper<User> {
@Select("select * from t_user where username=#{name}")
public User getUserByName(String name);
}
4.6.4. 创建服务接口
public interface UserService extends IService<User> {
public User getUserByName(String name);
}
4.6.5. 实现服务接口
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
@Autowired
UserMapper userMapper;
@Override
public User getUserByName(String name) {
return userMapper.getUserByName(name);
}
}
4.6.6. 创建API接口
@RestController
public class UserController {
@Autowired
UserService userService;
@GetMapping("/{name}")
public R getUserByName(@PathVariable String name){
return R.success(userService.getUserByName(name));
}
}
4.7. 启动微服务
4.7.1. 创建Spring Boot应用入口
@SpringBootApplication
public class UserApplication {
public static void main(String[] args) {
SpringApplication.run(UserApplication.class, args);
}
}
浏览器访问http://localhost:8001/user/user1
返回数据,说明项目能运行.

现在我们实现了第一个微服务项目, 虽然这仍然类似于单体项目,但已集成了Spring Cloud框架相关的依赖,并使用了不同于单体项目的配置文件。一个单体项目还不能明显地体现出微服务的项目结构, 接下来将创建第二个微服务.
5. 创建第二个微服务
第二个服务是micro-post
, 就是关于用户的帖子的, 同样为了简单, 只写了一个业务方法: 就是根据用户ID查询用户的帖子, 为了更简便, 只返回一篇帖子(如果存在的话).
5.1. 指定父项目
<parent>
<groupId>com.cengxuyuan</groupId>
<artifactId>micro-parent</artifactId>
<version>1.0-SNAPSHOT</version>
<relativePath>../micro-parent</relativePath>
</parent>
5.2. 增加MYSQL和Mybatis-plus依赖
<dependencies>
<!-- MySQL 驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!-- mybatis plus的依赖 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
</dependency>
</dependencies>
5.2.1. 添加cloud的基础环境包
<!--cloud的基础环境包-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-context</artifactId>
</dependency>
<dependency>
<groupId>com.cengxuyuan</groupId>
<artifactId>micro-common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
5.3. 创建post服务的数据库
不同的微服务之间使用不同的数据库.

5.4. 创建文章表
DROP TABLE IF EXISTS `t_post`;
CREATE TABLE `t_post` (
`post_id` int NOT NULL COMMENT '文章id',
`user_id` int NOT NULL COMMENT '用户id',
`title` varchar(200) NOT NULL COMMENT '文章标题',
`content` text NOT NULL COMMENT '文章内容',
`create_time` datetime NOT NULL COMMENT '创建时间',
PRIMARY KEY (`post_id`),
KEY `idx_post_id` (`post_id`)
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4;
INSERT INTO `t_post` (`post_id`, `user_id`, `title`, `content`, `create_time`) VALUES
(1, 1, 'Exciting News', 'Content of post 1 by user 1.', '2024-03-01 08:00:00'),
(2, 2, 'Tech Innovations', 'Content of post 2 by user 2.', '2024-03-01 09:00:00'),
(3, 3, 'Health and Wellness', 'Content of post 3 by user 3.', '2024-03-01 10:00:00'),
(4, 4, 'Travel Destinations', 'Content of post 4 by user 4.', '2024-03-01 11:00:00'),
(5, 5, 'Cooking Tips', 'Content of post 5 by user 5.', '2024-03-01 12:00:00'),
(6, 6, 'Financial Advice', 'Content of post 6 by user 6.', '2024-03-01 13:00:00'),
(7, 7, 'DIY Projects', 'Content of post 7 by user 7.', '2024-03-01 14:00:00'),
(8, 8, 'Sports Commentary', 'Content of post 8 by user 8.', '2024-03-01 15:00:00'),
(9, 9, 'Art and Culture', 'Content of post 9 by user 9.', '2024-03-01 16:00:00'),
(10, 10, 'Educational Resources', 'Content of post 10 by user 10.', '2024-03-01 17:00:00');
5.5. 增加配置文件
server:
servlet:
context-path: /post
port: 8002
spring:
application:
name: micro-post
profiles:
active: dev
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/micro-post?serverTimezone=UTC&useUnicode=true&useSSL=false
username: root
password: root
5.6. MVC架构搭建服务
5.6.1. 实现功能:根据用户ID查询用户文章
现实中一个用户可能有多篇文章,这里为了简便,不使用List和封装Page参数,这里只查询一篇文章。
5.6.2. 创建实体类
@Data
@TableName("t_post")
public class Post {
@TableId(value = "post_id", type = IdType.AUTO)
private Integer postId;
private Integer userId;
private String title;
private String content;
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
}
5.6.3. 创建Mapper层接口
@Mapper
public interface PostMapper extends BaseMapper<Post> {
@Select("select * from t_post where user_id=#{userId} limit 1")
public Post getPostByUserId(Integer userId);
}
5.6.4. 创建服务接口
public interface PostService extends IService<Post> {
public Post getPostByUserId(Integer userId);
}
5.6.5. 实现服务接口
@Service
public class PostServiceImpl extends ServiceImpl<PostMapper, Post> implements PostService {
@Autowired
PostMapper PostMapper;
@Override
public Post getPostByUserId(Integer userId) {
return PostMapper.getPostByUserId(userId);
}
}
5.6.6. 创建API接口
@RestController
public class PostController {
@Autowired
PostService postService;
@GetMapping("/user/{userId}")
public R getPostByUserId(@PathVariable Integer userId){
return R.success(postService.getPostByUserId(userId));
}
}
5.7. 启动微服务
5.7.1. 创建Spring Boot应用入口
@SpringBootApplication
public class PostApplication {
public static void main(String[] args) {
SpringApplication.run(PostApplication.class, args);
}
}
浏览器访问http://localhost:8002/post/user/1
返回数据

6. 搭建Nacos
访问:http://192.168.101.65:8848/nacos/
账号密码:nacos/nacos
创建命名空间

6.1. 服务注册
6.1.1. 添加依赖
在micro-user
的pom
中添加
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
6.1.2. 配置nacos地址
server:
servlet:
context-path: /user
port: 8001
spring:
application:
name: micro-user
profiles:
active: dev
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/micro-user?serverTimezone=UTC&useUnicode=true&useSSL=false
username: root
password: root
cloud:
nacos:
server-addr: 192.168.101.100:8848
discovery:
namespace: micro-dev
group: micro-project
同样给post
服务添加nacos配置
6.1.3. 启动服务

6.2. 实现配置中心
6.2.1. 添加配置依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
6.2.2. 修改本地配置文件
将部分配置移到nacos上配置,也就是将注释掉的配置放到nacos上配置
#server:
# servlet:
# context-path: /user
# port: 8001
spring:
application:
name: micro-user
profiles:
active: dev
# datasource:
# driver-class-name: com.mysql.cj.jdbc.Driver
# url: jdbc:mysql://localhost:3306/micro-user?serverTimezone=UTC&useUnicode=true&useSSL=false
# username: root
# password: root
为了能从nacos上获取注释掉的配置,需要增加下面的config配置
cloud:
nacos:
server-addr: 192.168.101.100:8848
discovery:
namespace: micro-dev
group: micro-project
config:
namespace: micro-dev
group: micro-project
file-extension: yaml
refresh-enabled: true
6.2.3. 在nacos上配置

6.2.4. 启动服务
可以运行
同样的道理,给post
服务的配置也放到nacos中
6.2.5. 公用配置
比如说log4j日志配置,swagger开发文档配置,远程调用配置等,后面讲到,配置大概如下:
config:
namespace: micro-dev
group: micro-project
file-extension: yaml
refresh-enabled: true
# 用于共享的配置文件
shared-configs:
- data-id: feign-${spring.profiles.active}.yaml
group: micro-shared
refresh: true
6.3. 搭建网关
6.3.1. 创建网关项目
6.3.1.1. 指定父项目
<parent>
<groupId>com.cengxuyuan</groupId>
<artifactId>micro-parent</artifactId>
<version>1.0-SNAPSHOT</version>
<relativePath>../micro-parent</relativePath>
</parent>
6.3.1.2. 添加依赖
<dependencies>
<!--网关-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!--服务发现中心-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!-- 排除 Spring Boot 依赖的日志包冲突 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
</dependencies>
6.3.1.3. 添加配置文件
spring:
application:
name: micro-gateway
profiles:
active: dev
cloud:
nacos:
server-addr: 192.168.101.100:8848
discovery:
namespace: micro-dev
group: micro-project
config:
namespace: micro-dev
group: micro-project
file-extension: yaml
refresh-enabled: true
6.3.1.4. 在nacos上配置网关路由
server:
port: 8888 # 网关端口
spring:
cloud:
gateway:
routes: # 网关路由配置
- id: user-api # 路由id,自定义,只要唯一即可
uri: lb://micro-user # 路由的目标地址 lb就是负载均衡,后面跟服务名称
predicates: # 路由断言,也就是判断请求是否符合路由规则的条件
- Path=/user/** # 这个是按照路径匹配,只要以/user/开头就符合要求
- id: post-api
uri: lb://micro-post
predicates:
- Path=/post/**

6.3.1.5. 创建启动类
@SpringBootApplication
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
}
6.3.1.6. 启动
通过网关服务访问其他微服务,在浏览器上访问http://localhost:8888/user/user1

7. 使用Feign实现远程调用
user服务调用post服务,根据username查询用户的文章。
7.1. 添加依赖
<!-- Spring Cloud 微服务远程调用 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
</dependency>
7.2. 在nacos配置feign配置文件

feign:
client:
config:
default: # default全局的配置
loggerLevel: BASIC # 日志级别,BASIC就是基本的请求和响应信息
hystrix:
enabled: true
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 10000 # 设置hystrix的超时时间为10秒
circuitbreaker:
enabled: true
httpclient:
enabled: true # 开启feign对HttpClient的支持
max-connections: 200 # 最大的连接数
max-connections-per-route: 50 # 每个路径的最大连接数
7.3. 在user服务引用配置文件
config:
namespace: micro-dev
group: micro-project
file-extension: yaml
refresh-enabled: true
shared-configs:
- data-id: feign-${spring.profiles.active}.yaml
group: micro-shared
refresh: true
7.4. 编写feign服务接口
@FeignClient(value = "micro-post")
public interface PostServiceClient {
@GetMapping(path = "/post/user/{userId}")
R getPostByUserId(@PathVariable("userId") Integer userId);
}
在Spring Cloud版本Hoxton及以后(包括你使用的Spring Cloud OpenFeign 2.2.6.RELEASE
),@PathVariable
注解不能缺少变量名称,我们需要显式地指定@PathVariable
中的名称。
7.5. 启动类上添加注解
@EnableFeignClients(basePackages = {"com.cengxuyuan.feignclient"})
@SpringBootApplication
public class UserApplication {
public static void main(String[] args) {
SpringApplication.run(UserApplication.class, args);
}
}
7.6. 在user服务上测试
7.6.1. 注入client并编写测试方法
@RestController
public class UserController {
@Autowired
UserService userService;
@Autowired
PostServiceClient postServiceClient;
@GetMapping("/{name}")
public R getUserByName(@PathVariable String name){
return R.success(userService.getUserByName(name));
}
@GetMapping("/feign/{name}")
public R testFeign(@PathVariable String name){
User user = userService.getUserByName(name);
R post = postServiceClient.getPostByUserId(user.getUserId());
return post;
}
}
7.6.2. 启动服务进行测试
在浏览器输入http://localhost:8001/user/feign/user1
得到输出结果,可以知道访问user
微服务和post
微服务成功。

8. 实现熔断降级
在nacos
中的feign-dev.yaml
增加如下配置, 前面已经增加了,这里说明一下作用
feign:
hystrix:
enabled: true
circuitbreaker:
enabled: true
这段配置表示你希望启用Feign
集成的Spring Cloud Circuit Breaker
支持。这允许你使用Spring Cloud Circuit Breaker
提供的抽象来管理断路器行为,而不是直接依赖于Hystrix
或其他具体实现。这种方式提供了更大的灵活性,因为你可以根据需要更换不同的断路器实现,而不必修改业务代码。
8.1. 指定FallbackFactory 实现降级
@FeignClient(value = "micro-post", fallbackFactory = PostServiceClientFallbackFactory.class)
public interface PostServiceClient {
@GetMapping(path = "/post/user/{userId}")
R getPostByUserId(@PathVariable("userId") Integer userId);
}
8.2. 实现FallbackFactory
这种方法可以拿到异常信息。
@Component
public class PostServiceClientFallbackFactory implements FallbackFactory<PostServiceClient> {
@Override
public PostServiceClient create(Throwable throwable) {
return new PostServiceClient() {
@Override
public R getPostByUserId(Integer userId) {
return R.error("getPostByUserId降级");
}
};
}
}
8.3. 启动服务进行测试
首先访问http://localhost:8001/user/feign/user1
,是可以正常访问的,
现在关闭post微服务来认为制造异常,观察是否执行熔断降级。
重新访问http://localhost:8001/user/feign/user1
,可以看到,出现异常后执行了FallbackFactory中的降级处理。

9. 总结
通过上面的教程,我们已经学习了如何构建一个基于Spring Cloud框架的微服务架构项目,并且掌握了各种工具和技术的使用方法。
在微服务的搭建过程中,我们使用了Nacos作为服务注册中心,在Nacos上配置路由信息和共享配置。同时,我们还使用Spring Cloud Gateway创建网关,并且在Nacos上配置网关路由信息。
在远程调用方面,我们使用了Feign实现远程调用其他微服务,并且在Nacos上配置Feign的配置文件。最后,我们还学习了如何使用熔断降级机制来处理异常情况,保证系统的稳定性。
总的来说,本教程展示了微服务的基本架构,涵盖了以下内容:
-
创建并配置Nacos作为服务注册中心和配置中心 -
使用Spring Cloud Gateway创建网关,并配置网关路由信息 -
使用Feign实现微服务之间的远程调用,并进行相应的配置 -
实现熔断降级机制以提高系统的稳定性
希望这次的教程能够为你的技术之路添砖加瓦。
原文始发于微信公众号(曾续缘):如何从 0 搭建微服务?
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/256728.html