news 2026/5/23 8:21:52

从0到1构建企业级微服务项目实战手册(精简版)(Spring Boot + Docker + CI/CD)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
从0到1构建企业级微服务项目实战手册(精简版)(Spring Boot + Docker + CI/CD)

视频看了几百小时还迷糊?关注我,几分钟让你秒懂!


本手册将手把手带你从零搭建一个生产可用的分布式微服务系统,涵盖架构设计、核心组件封装、中间件集成、容器化部署与自动化流水线。内容面向 Java 项目 Leader,注重工程落地性可维护性

全书分为六章,每章均含详细说明、代码示例、反例警示与最佳实践。


第一章:从0到1构建微服务架构

1.1 微服务选型与项目结构

✅ 正确做法:多模块 Maven 项目结构
my-shop/ ├── pom.xml # 父POM,统一管理依赖版本 ├── my-shop-gateway/ # API网关 ├── my-shop-auth/ # 鉴权中心(JWT/OAuth2) ├── my-shop-user/ # 用户服务 ├── my-shop-order/ # 订单服务 ├── my-shop-common/ # 公共模块(工具类、异常、DTO等) └── my-shop-starter/ # 自定义Starter(如租户、上下文)

父 POM 关键配置(pom.xml)

<properties> <spring-boot.version>3.2.5</spring-boot.version> <spring-cloud.version>2023.0.0</spring-cloud.version> <mybatis-plus.version>3.5.5</mybatis-plus.version> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>${spring-boot.version}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>${mybatis-plus.version}</version> </dependency> </dependencies> </dependencyManagement>

💡为什么这样用?
统一依赖版本避免“Jar Hell”,多模块解耦便于团队协作和独立部署。


1.2 网关(Spring Cloud Gateway)

场景:所有请求经网关路由 + 鉴权

my-shop-gateway/pom.xml

<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>

application.yml

spring: cloud: gateway: routes: - id: user-service uri: lb://my-shop-user # 基于Nacos服务发现 predicates: - Path=/api/user/** filters: - StripPrefix=1
自定义全局过滤器(鉴权)
@Component public class AuthGlobalFilter implements GlobalFilter, Ordered { @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { String token = exchange.getRequest().getHeaders().getFirst("Authorization"); if (token == null || !token.startsWith("Bearer ")) { exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED); return exchange.getResponse().setComplete(); } // 可调用 auth 服务校验 token return chain.filter(exchange); } @Override public int getOrder() { return -100; // 优先级高 } }

反例:在每个微服务里重复写鉴权逻辑 → 代码冗余、难以维护。
正解:网关统一拦截,auth 服务提供 token 校验 API。


1.3 鉴权中心(JWT + Spring Security)

my-shop-auth 模块核心逻辑

// 登录接口 @PostMapping("/login") public ResponseEntity<TokenDTO> login(@RequestBody LoginDTO dto) { // 1. 校验用户名密码 User user = userService.validate(dto.getUsername(), dto.getPassword()); if (user == null) throw new BadCredentialsException("Invalid credentials"); // 2. 生成 JWT(含用户ID、租户ID、角色) String token = JwtUtil.createToken(user.getId(), user.getTenantId(), user.getRoles()); return ResponseEntity.ok(new TokenDTO(token)); }

JwtUtil.java

public class JwtUtil { private static final String SECRET = "myShopSecretKey2025"; private static final long EXPIRATION = 86400000; // 24h public static String createToken(Long userId, String tenantId, List<String> roles) { return Jwts.builder() .claim("userId", userId) .claim("tenantId", tenantId) .claim("roles", roles) .setIssuedAt(new Date()) .setExpiration(new Date(System.currentTimeMillis() + EXPIRATION)) .signWith(SignatureAlgorithm.HS512, SECRET) .compact(); } public static Claims parseToken(String token) { return Jwts.parser() .setSigningKey(SECRET) .parseClaimsJws(token.replace("Bearer ", "")) .getBody(); } }

⚠️注意事项

  • SECRET 必须配置在配置中心(如 Nacos),不可硬编码。
  • 生产环境建议使用 RSA 非对称加密。

第二章:核心组件封装

2.1 MyBatis-Plus 封装

my-shop-common 模块中定义 BaseMapper

@Mapper public interface MyBaseMapper<T> extends BaseMapper<T> { // 可扩展逻辑删除、自动填充等 }

实体类自动填充创建时间/更新时间

@Data public class BaseEntity { @TableField(fill = FieldFill.INSERT) private LocalDateTime createTime; @TableField(fill = FieldFill.INSERT_UPDATE) private LocalDateTime updateTime; } @Component public class MyMetaObjectHandler implements MetaObjectHandler { @Override public void insertFill(MetaObject metaObject) { this.strictInsertFill(metaObject, "createTime", LocalDateTime::now, LocalDateTime.class); this.strictUpdateFill(metaObject, "updateTime", LocalDateTime::now, LocalDateTime.class); } @Override public void updateFill(MetaObject metaObject) { this.strictUpdateFill(metaObject, "updateTime", LocalDateTime::now, LocalDateTime.class); } }

优势:避免每个实体重复写时间字段,提升开发效率。


2.2 多租户支持(基于 Schema 隔离)

场景:SaaS 系统,每个租户数据独立。

方案:动态数据源 + MyBatis-Plus 租户插件

  1. 租户上下文
public class TenantContext { private static final ThreadLocal<String> TENANT_ID = new ThreadLocal<>(); public static void setTenantId(String tenantId) { TENANT_ID.set(tenantId); } public static String getTenantId() { return TENANT_ID.get(); } public static void clear() { TENANT_ID.remove(); } }
  1. 自定义租户处理器
@Component public class MyTenantLineHandler implements TenantLineHandler { @Override public Expression getTenantId() { String tenantId = TenantContext.getTenantId(); if (tenantId == null) { throw new RuntimeException("Tenant ID not found in context!"); } return new StringValue(tenantId); } @Override public boolean ignoreTable(String tableName) { return "sys_tenant".equals(tableName); // 租户表不加条件 } }
  1. 注册插件
@Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterpreter(); interceptor.addInnerInterceptor(new TenantLineInnerInterceptor(new MyTenantLineHandler())); return interceptor; }

反例:在 SQL 中手动拼接WHERE tenant_id = ?→ 容易遗漏,安全风险高。
正解:通过插件自动注入,100% 覆盖。


2.3 上下文信息封装(Request Context)

目标:在任意 Service 层获取当前用户、租户、TraceID。

public class RequestContext { private static final ThreadLocal<UserInfo> USER_INFO = new ThreadLocal<>(); public static void set(UserInfo info) { USER_INFO.set(info); } public static UserInfo getUserInfo() { return USER_INFO.get(); } public static void clear() { USER_INFO.remove(); } }

在网关或拦截器中设置

// 在 AuthGlobalFilter 或 WebMvcConfigurer 中 Claims claims = JwtUtil.parseToken(token); UserInfo user = new UserInfo(claims.get("userId", Long.class), claims.get("tenantId", String.class)); RequestContext.set(user);

⚠️重要:必须在请求结束时clear(),否则 ThreadLocal 内存泄漏!


第三章:中间件容器化部署与集成

3.1 使用 Docker Compose 一键启动中间件

docker-compose.yml

version: '3.8' services: mysql: image: mysql:8.0 environment: MYSQL_ROOT_PASSWORD: root123 MYSQL_DATABASE: my_shop ports: - "3306:3306" volumes: - ./mysql/data:/var/lib/mysql redis: image: redis:7.0 ports: - "6379:6379" rabbitmq: image: rabbitmq:3.12-management ports: - "5672:5672" - "15672:15672" environment: RABBITMQ_DEFAULT_USER: admin RABBITMQ_DEFAULT_PASS: admin123 elasticsearch: image: elasticsearch:8.9.0 environment: discovery.type: single-node xpack.security.enabled: "false" ports: - "9200:9200" kibana: image: kibana:8.9.0 depends_on: - elasticsearch ports: - "5601:5601"

启动命令:

docker-compose up -d

3.2 Spring Boot 集成各中间件

Redis 配置(application.yml):
spring: redis: host: localhost port: 6379 lettuce: pool: max-active: 8
RabbitMQ 生产者示例:
@Autowired private RabbitTemplate rabbitTemplate; public void sendOrderCreated(Long orderId) { rabbitTemplate.convertAndSend("order.exchange", "order.created", orderId); }
Elasticsearch Repository:
public interface ProductRepository extends ElasticsearchRepository<Product, String> { List<Product> findByNameContaining(String name); }

最佳实践:所有中间件连接信息应从配置中心读取,而非写死在 yml。


第四章:Docker 容器化部署

4.1 为每个微服务编写 Dockerfile

my-shop-user/Dockerfile

FROM openjdk:17-jdk-slim COPY target/my-shop-user.jar /app.jar EXPOSE 8081 ENTRYPOINT ["java", "-jar", "/app.jar"]

4.2 构建镜像并运行

# 构建 ./mvnw clean package -DskipTests docker build -t my-shop-user:1.0 . # 运行(连接到 docker-compose 网络) docker run --network my-shop_default -p 8081:8081 my-shop-user:1.0

⚠️注意:微服务之间通过服务名通信(如http://my-shop-user:8081),而非 localhost。


第五章:CI/CD 流水线搭建(GitLab CI 示例)

.gitlab-ci.yml

stages: - build - test - deploy variables: DOCKER_HOST: tcp://docker:2375 DOCKER_TLS_CERTDIR: "" build: stage: build script: - ./mvnw clean package -DskipTests - docker build -t $CI_REGISTRY_IMAGE/user:$CI_COMMIT_SHORT_SHA ./my-shop-user - docker push $CI_REGISTRY_IMAGE/user:$CI_COMMIT_SHORT_SHA deploy-prod: stage: deploy script: - ssh user@prod-server "docker pull $CI_REGISTRY_IMAGE/user:$CI_COMMIT_SHORT_SHA && docker stop user || true && docker rm user || true" - ssh user@prod-server "docker run -d --name user --network host $CI_REGISTRY_IMAGE/user:$CI_COMMIT_SHORT_SHA" only: - main

关键点:自动化测试、镜像版本控制、滚动发布。


第六章:Nginx 反向代理与 HTTPS

6.1 nginx.conf 配置

upstream gateway { server my-shop-gateway:8080; # Docker 内部服务名 } server { listen 80; server_name api.myshop.com; location / { proxy_pass http://gateway; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }

6.2 前端静态资源托管

server { listen 80; server_name www.myshop.com; root /usr/share/nginx/html; index index.html; location / { try_files $uri $uri/ /index.html; } }

🔒生产建议:配置 Let's Encrypt 免费 SSL 证书,强制 HTTPS。


总结

作为 Java 项目 Leader,你不仅要会写代码,更要掌控整个交付链路

  • 架构清晰(网关+鉴权+服务拆分)
  • 组件可复用(租户、上下文、MyBatis-Plus)
  • 中间件标准化(Docker Compose 管理)
  • 部署自动化(CI/CD + Docker)
  • 运维可观测(Nginx + ELK)

这套体系已在多个 SaaS 项目中验证,稳定支撑日活百万用户。

从0-1搞一个分布式微服务系统上线,要是细讲内容还是很多的,先写个大概,看下数据,后面有没有必要出一个超级详细版的

视频看了几百小时还迷糊?关注我,几分钟让你秒懂!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/22 20:03:18

Open-AutoGLM落地挑战全解析,破解手机端模型推理延迟与功耗难题

第一章&#xff1a;Open-AutoGLM移动端落地的技术背景 随着大语言模型在自然语言处理领域的广泛应用&#xff0c;将高性能模型部署至移动端设备成为实现低延迟、高隐私交互的关键路径。Open-AutoGLM作为基于AutoGLM架构开源的轻量化推理引擎&#xff0c;致力于在资源受限的移动…

作者头像 李华
网站建设 2026/5/23 1:10:57

揭秘Open-AutoGLM本地部署难题:5步实现高效AI模型落地

第一章&#xff1a;揭秘Open-AutoGLM本地部署难题&#xff1a;5步实现高效AI模型落地在本地环境中部署像Open-AutoGLM这样的大型语言模型&#xff0c;常面临依赖冲突、显存不足和推理延迟等挑战。通过系统化的部署流程&#xff0c;可显著提升模型落地效率与稳定性。环境准备与依…

作者头像 李华
网站建设 2026/5/20 21:30:53

深度学习yolov8训练混凝土缺陷检测数据集 深度学习基于YOLOV8混凝土识别裂缝检测系统UI界面 检测出现的外露钢筋,生锈,裂缝,剥落,风化,分层

深度学习中 构建一个用于混凝土缺陷检测的 YOLOv8 系统&#xff0c;包括数据集准备、模型训练、评估以及 GUI 应用程序开发。 文章目录1. 数据集准备**XML 转 YOLO 格式**2. 数据集预处理3. 安装依赖4. 配置 YOLOv85. 训练模型6. 评估模型7. 构建 GUI 应用程序8. 运行应用程序仅…

作者头像 李华
网站建设 2026/5/20 15:58:44

Dify平台自动补全功能在代码生成中的应用尝试

Dify平台自动补全功能在代码生成中的应用尝试 在现代软件开发节奏日益加快的今天&#xff0c;开发者每天都在与重复性编码、上下文切换和知识孤岛作斗争。一个函数写了一半&#xff0c;却要翻三四个历史项目找相似实现&#xff1b;新成员入职三个月仍写不出符合团队风格的代码…

作者头像 李华
网站建设 2026/5/22 2:46:02

从功能测试到测试开发:我的技能栈升级路线图

作为一名在软件测试领域摸爬滚打多年的从业者&#xff0c;我深知功能测试是职业生涯的基石——它教会我如何手动执行用例、发现缺陷&#xff0c;并确保产品质量。但随着行业向敏捷和DevOps转型&#xff0c;测试开发&#xff08;Test Development&#xff09;的需求日益增长&…

作者头像 李华
网站建设 2026/5/21 1:22:59

2025最新!9个AI论文平台测评:研究生开题报告必备指南

2025最新&#xff01;9个AI论文平台测评&#xff1a;研究生开题报告必备指南 2025年AI论文平台测评&#xff1a;为研究生开题报告提供科学参考 随着人工智能技术的不断进步&#xff0c;AI论文平台逐渐成为研究生在撰写开题报告、文献综述及论文写作过程中的重要工具。然而&…

作者头像 李华