视频看了几百小时还迷糊?关注我,几分钟让你秒懂!
本手册将手把手带你从零搭建一个生产可用的分布式微服务系统,涵盖架构设计、核心组件封装、中间件集成、容器化部署与自动化流水线。内容面向 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 租户插件
- 租户上下文:
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(); } }- 自定义租户处理器:
@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); // 租户表不加条件 } }- 注册插件:
@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 -d3.2 Spring Boot 集成各中间件
Redis 配置(application.yml):
spring: redis: host: localhost port: 6379 lettuce: pool: max-active: 8RabbitMQ 生产者示例:
@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搞一个分布式微服务系统上线,要是细讲内容还是很多的,先写个大概,看下数据,后面有没有必要出一个超级详细版的
视频看了几百小时还迷糊?关注我,几分钟让你秒懂!