零基础学Java——第十一章:实战项目 - 微服务入门

news2025/5/19 16:58:08

第十一章:实战项目 - 微服务入门

随着互联网应用的复杂性不断增加,单体应用(Monolithic Application)在可扩展性、可维护性、技术栈灵活性等方面逐渐暴露出一些问题。微服务架构(Microservices Architecture)应运而生,成为构建大型复杂应用的一种流行方式。

1. 什么是微服务?

微服务是一种架构风格,它将一个大型复杂应用拆分成一组小型的、独立部署的服务。每个服务都围绕特定的业务能力构建,并且可以独立开发、测试、部署和扩展。

核心思想

  • 单一职责:每个微服务只关注一项特定的业务功能。
  • 独立部署:每个微服务都可以独立部署,不依赖于其他服务的部署周期。
  • 技术异构性:不同的微服务可以使用不同的编程语言、数据库或技术栈。
  • 去中心化治理:团队可以独立负责自己的服务,包括技术选型和数据管理。
  • 弹性与容错:单个服务的故障不会导致整个系统崩溃。

生活中的例子

想象一个大型电商平台。如果采用单体架构,所有的功能(用户管理、商品管理、订单管理、支付、库存等)都在一个巨大的代码库中。如果采用微服务架构,这些功能会被拆分成独立的服务:

  • 用户服务 (User Service)
  • 商品服务 (Product Service)
  • 订单服务 (Order Service)
  • 支付服务 (Payment Service)
  • 库存服务 (Inventory Service)

这些服务之间通过轻量级的通信机制(通常是HTTP/REST API或消息队列)进行交互。

2. 微服务与单体应用的对比

特性单体应用 (Monolithic)微服务 (Microservices)
代码库单一、庞大多个、小型、独立
部署整个应用作为一个单元部署每个服务独立部署
扩展性整体扩展,难以针对特定功能进行精细化扩展可针对每个服务独立扩展
技术栈通常统一技术栈不同服务可采用不同技术栈
开发效率初期快,后期因代码耦合和复杂性增加而变慢初期可能较慢(需要处理分布式问题),后期因独立性而提高
容错性单点故障可能导致整个应用不可用单个服务故障影响范围有限,系统更具弹性
团队协作大型团队在单一代码库上协作可能存在冲突和瓶颈小型自治团队负责各自服务,并行开发效率高
复杂性应用内部复杂性高分布式系统带来的运维和管理复杂性高

3. 微服务的优势

  • 技术多样性:可以为每个服务选择最适合的技术栈。
  • 弹性伸缩:可以根据每个服务的负载情况独立进行伸缩。
  • 易于维护和理解:每个服务代码量小,业务逻辑清晰。
  • 独立部署,快速迭代:单个服务的修改和部署不影响其他服务,可以更快地交付新功能。
  • 更好的故障隔离:一个服务的故障不会轻易导致整个系统瘫痪。
  • 团队自治:小型团队可以独立负责一个或多个服务,提高开发效率和责任感。

4. 微服务的挑战

  • 分布式系统复杂性:需要处理网络延迟、服务间通信、数据一致性等问题。
  • 运维成本:需要管理和监控大量的服务实例,对自动化运维能力要求高。
  • 测试复杂性:端到端测试和集成测试变得更加复杂。
  • 服务发现与注册:需要机制来动态发现和注册服务实例。
  • 配置管理:需要统一管理各个服务的配置。
  • 链路追踪与监控:需要工具来追踪跨多个服务的请求,并监控系统健康状况。
  • 数据一致性:在分布式环境中保证数据最终一致性是一个挑战。

5. Java 微服务技术栈概览

Java生态系统为构建微服务提供了丰富的框架和工具。

5.1 Spring Boot

Spring Boot是构建Java微服务的首选框架。它简化了Spring应用的创建和部署,并且内置了对常见微服务模式的支持。

5.2 Spring Cloud

Spring Cloud是基于Spring Boot的一系列框架的有序集合,用于快速构建分布式系统中的一些常见模式(例如,配置管理、服务发现、断路器、智能路由、微代理、控制总线、一次性令牌、全局锁、领导选举、分布式会话、集群状态)。

Spring Cloud 核心组件

  • 服务发现与注册 (Service Discovery & Registration)
    • Netflix Eureka (维护模式,推荐使用Consul或Nacos)
    • HashiCorp Consul
    • Alibaba Nacos
  • 客户端负载均衡 (Client-side Load Balancing)
    • Netflix Ribbon (维护模式,Spring Cloud LoadBalancer是推荐替代方案)
    • Spring Cloud LoadBalancer
  • 声明式REST客户端 (Declarative REST Client)
    • Netflix Feign (现在是OpenFeign)
    • Spring Cloud OpenFeign
  • API网关 (API Gateway)
    • Netflix Zuul (Zuul 1维护模式,Zuul 2不被Spring Cloud直接支持)
    • Spring Cloud Gateway (推荐)
  • 断路器 (Circuit Breaker)
    • Netflix Hystrix (维护模式)
    • Resilience4j (推荐)
    • Sentinel (Alibaba)
  • 配置中心 (Configuration Management)
    • Spring Cloud Config Server
    • HashiCorp Consul
    • Alibaba Nacos
  • 消息总线 (Message Bus)
    • Spring Cloud Bus (通常与Spring Cloud Config配合使用,实现配置动态刷新)
  • 分布式追踪 (Distributed Tracing)
    • Spring Cloud Sleuth (通常与Zipkin或Jaeger集成)

6. 构建一个简单的微服务示例 (使用 Spring Boot)

让我们构思两个简单的微服务:一个“问候服务”(Greeting Service)和一个“用户服务”(User Service)。“问候服务”会调用“用户服务”来获取用户名,然后返回个性化的问候语。

6.1 创建用户服务 (User Service)

  1. 使用 Spring Initializr 创建项目:
    • Group: com.example.microservices
    • Artifact: user-service
    • Dependencies: Spring Web
  2. 创建 User POJO:
    package com.example.microservices.userservice;
    
    public class User {
        private Long id;
        private String username;
    
        public User(Long id, String username) {
            this.id = id;
            this.username = username;
        }
    
        // Getters and Setters
        public Long getId() { return id; }
        public void setId(Long id) { this.id = id; }
        public String getUsername() { return username; }
        public void setUsername(String username) { this.username = username; }
    }
    
  3. 创建 UserController:
    package com.example.microservices.userservice;
    
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import java.util.HashMap;
    import java.util.Map;
    
    @RestController
    @RequestMapping("/users")
    public class UserController {
        private final Map<Long, User> users = new HashMap<>();
    
        public UserController() {
            users.put(1L, new User(1L, "Alice"));
            users.put(2L, new User(2L, "Bob"));
        }
    
        @GetMapping("/{id}")
        public User getUserById(@PathVariable Long id) {
            System.out.println("User Service: Received request for user ID: " + id);
            return users.getOrDefault(id, new User(0L, "Unknown"));
        }
    }
    
  4. 配置端口 (可选,避免冲突): 在 application.properties 中设置:
    server.port=8081
    
  5. 运行 User Service.
    测试:访问 http://localhost:8081/users/1,应返回 {"id":1,"username":"Alice"}

6.2 创建问候服务 (Greeting Service)

  1. 使用 Spring Initializr 创建项目:
    • Group: com.example.microservices
    • Artifact: greeting-service
    • Dependencies: Spring Web, Spring Boot Actuator (可选,用于健康检查等)
  2. 创建 User DTO (Data Transfer Object) (用于接收来自User Service的数据):
    package com.example.microservices.greetingservice;
    
    // 这个类结构需要和User Service返回的User对象一致
    public class User {
        private Long id;
        private String username;
    
        // Getters and Setters
        public Long getId() { return id; }
        public void setId(Long id) { this.id = id; }
        public String getUsername() { return username; }
        public void setUsername(String username) { this.username = username; }
    }
    
  3. 创建 GreetingController:
    package com.example.microservices.greetingservice;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RestController;
    import org.springframework.web.client.RestTemplate;
    
    @RestController
    public class GreetingController {
    
        // RestTemplate用于进行HTTP调用
        private final RestTemplate restTemplate;
    
        @Autowired
        public GreetingController(RestTemplate restTemplate) {
            this.restTemplate = restTemplate;
        }
    
        @GetMapping("/greet/{userId}")
        public String greetUser(@PathVariable Long userId) {
            System.out.println("Greeting Service: Received request for user ID: " + userId);
            // 调用User Service获取用户信息
            // 注意:这里硬编码了User Service的地址,实际项目中应使用服务发现
            String userServiceUrl = "http://localhost:8081/users/" + userId;
            User user = restTemplate.getForObject(userServiceUrl, User.class);
    
            if (user != null && !"Unknown".equals(user.getUsername())) {
                return "Hello, " + user.getUsername() + "!";
            } else {
                return "Hello, Anonymous User!";
            }
        }
    }
    
  4. 配置 RestTemplate Bean (在主应用类中添加):
    package com.example.microservices.greetingservice;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.context.annotation.Bean;
    import org.springframework.web.client.RestTemplate;
    
    @SpringBootApplication
    public class GreetingServiceApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(GreetingServiceApplication.class, args);
        }
    
        @Bean // 将RestTemplate注册为一个Bean,Spring会管理它的生命周期
        public RestTemplate restTemplate() {
            return new RestTemplate();
        }
    }
    
  5. 配置端口: 在 application.properties 中设置 (例如 server.port=8082)。
  6. 运行 Greeting Service.
    测试:访问 http://localhost:8082/greet/1。Greeting Service会调用User Service,然后返回 Hello, Alice!
    如果User Service未运行或ID不存在,可能会返回 Hello, Anonymous User! 或报错。

注意:这个例子非常基础,它硬编码了服务地址。在实际的微服务架构中,你需要使用服务发现机制(如Eureka, Consul, Nacos)和客户端负载均衡(如Spring Cloud LoadBalancer)来动态查找和调用服务。

7. 服务发现与注册 (以 Nacos 为例,概念性介绍)

当微服务数量增多,手动管理它们的地址和端口变得不现实。服务发现与注册中心解决了这个问题。

  • 服务注册:每个微服务实例在启动时,向注册中心注册自己的网络位置(IP地址、端口号)和其他元数据。
  • 服务发现:当一个服务(如Greeting Service)需要调用另一个服务(如User Service)时,它会向注册中心查询User Service的可用实例列表。
  • 健康检查:注册中心会定期检查已注册服务的健康状况,并剔除不健康的实例。

Alibaba Nacos 是一个功能丰富的平台,提供服务发现、配置管理和服务管理。

大致流程

  1. 启动 Nacos Server
  2. User Service 配置:
    • 添加 Nacos Discovery Starter 依赖 (spring-cloud-starter-alibaba-nacos-discovery)。
    • application.properties 中配置 Nacos Server 地址和应用名:
      spring.application.name=user-service
      spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
      
    • 在主类上添加 @EnableDiscoveryClient 注解。
  3. Greeting Service 配置:
    • 添加 Nacos Discovery Starter 依赖。
    • 配置 Nacos Server 地址和应用名 (spring.application.name=greeting-service)。
    • 在主类上添加 @EnableDiscoveryClient 注解。
    • 修改 RestTemplate Bean,添加 @LoadBalanced 注解,使其能够通过服务名进行调用:
      @Bean
      @LoadBalanced // 开启负载均衡
      public RestTemplate restTemplate() {
          return new RestTemplate();
      }
      
    • 修改 GreetingController 中调用User Service的URL,使用服务名代替硬编码的IP和端口:
      // String userServiceUrl = "http://localhost:8081/users/" + userId; // 旧方式
      String userServiceUrl = "http://user-service/users/" + userId; // 新方式,user-service是User Service在Nacos中注册的服务名
      

当Greeting Service通过 http://user-service/... 调用时,Spring Cloud LoadBalancer (集成了Ribbon的功能) 会从Nacos获取 user-service 的可用实例列表,并选择一个实例进行调用。

8. API 网关 (以 Spring Cloud Gateway 为例,概念性介绍)

当微服务数量众多时,客户端直接与所有微服务通信会变得复杂且难以管理。API网关作为系统的唯一入口,提供了请求路由、聚合、安全、监控等功能。

Spring Cloud Gateway 是一个基于Spring Framework 5, Project Reactor和Spring Boot 2构建的API网关。

主要功能

  • 路由 (Routing):根据请求的路径、头部等信息将请求转发到后端相应的微服务。
  • 断言 (Predicates):匹配HTTP请求中的任何内容,如路径、方法、头部等,用于决定路由规则是否适用。
  • 过滤器 (Filters):在请求被路由前后执行一些逻辑,如修改请求/响应、认证、限流等。

大致配置

  1. 创建一个新的Spring Boot项目,添加 Spring Cloud Gateway 依赖。
  2. application.propertiesapplication.yml 中配置路由规则:
    spring:
      application:
        name: api-gateway
      cloud:
        gateway:
          discovery:
            locator:
              enabled: true # 开启从注册中心自动发现服务并创建路由
              lower-case-service-id: true # 将服务名转为小写作为路径前缀
          routes:
            - id: user_service_route # 路由ID,唯一即可
              uri: lb://user-service # lb:// 表示从注册中心负载均衡地选择 user-service 实例
              predicates:
                - Path=/api/users/** # 当请求路径匹配 /api/users/** 时,应用此路由
              # filters: # 可以添加过滤器
                # - StripPrefix=1 # 例如,去掉路径中的第一个前缀 /api
    
            - id: greeting_service_route
              uri: lb://greeting-service
              predicates:
                - Path=/api/greetings/**
    server:
      port: 8080 # 网关端口
    
    如果开启了 discovery.locator.enabled=true,Gateway会自动为注册中心中的每个服务创建一个路由,路径通常是 /服务名小写/**。例如,可以直接通过 http://localhost:8080/user-service/users/1 访问User Service。

客户端现在只需要与API网关 (如 http://localhost:8080) 通信,网关会将请求路由到相应的后端微服务。

9. 总结与下一步

微服务架构为构建大型、复杂的分布式系统提供了一种灵活且可扩展的方式。Spring Boot和Spring Cloud为Java开发者构建微服务提供了强大的支持。

入门微服务需要掌握的关键概念

  • 服务拆分原则
  • 服务间通信 (REST API, 消息队列)
  • 服务发现与注册
  • 客户端负载均衡
  • API网关
  • 断路器与容错
  • 配置管理
  • 分布式追踪与监控

下一步可以探索的内容

  • 深入学习 Spring Cloud 各个组件:如Nacos/Consul, OpenFeign, Resilience4j, Spring Cloud Gateway, Spring Cloud Config等。
  • 容器化与编排:学习Docker和Kubernetes,用于微服务的打包、部署和管理。
  • 消息队列:学习RabbitMQ, Kafka等,实现异步通信和解耦。
  • 分布式事务:了解Saga模式、TCC模式等处理分布式事务的方案。
  • DevOps实践:学习CI/CD(持续集成/持续交付)流程,实现微服务的自动化构建、测试和部署。

微服务是一个庞大且不断发展的领域。从小处着手,逐步实践,你会慢慢掌握它的精髓。祝你学习愉快!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2379419.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

docker 学习记录

docker pull nginx docker 将本地nginx快照保存到当前文件夹下 docker save -o nginx.tar nginx:latestdocker 将本地nginx 加载 docker load -i nginx.tar docker运行nginx在80端口 docker run --name dnginx -p 80:80 -d nginxredis启动 docker run --name mr -p 6379:6379 -…

南京邮电大学金工实习答案

一、金工实习的定义 金工实习是机械类专业学生一项重要的实践课程&#xff0c;它绝非仅仅只是理论知识在操作层面的简单验证&#xff0c;而是一个全方位培养学生综合实践能力与职业素养的系统工程。从本质上而言&#xff0c;金工实习是学生走出教室&#xff0c;亲身踏入机械加…

世界模型+大模型+自动驾驶 论文小汇总

最近看了一些论文&#xff0c;懒得一个个写博客了&#xff0c;直接汇总起来 文章目录 大模型VLM-ADVLM-E2EOpenDriveVLAFASIONAD&#xff1a;自适应反馈的类人自动驾驶中快速和慢速思维融合系统快系统慢系统快慢结合 世界模型End-to-End Driving with Online Trajectory Evalu…

C++函数三剑客:缺省参数·函数重载·引用的高效编程指南

前引&#xff1a;在C编程中&#xff0c;缺省参数、函数重载、引用是提升代码简洁性、复用性和效率的三大核心机制。它们既能减少冗杂的代码&#xff0c;又能增强接口设计的灵活性。本文将通过清晰的理论解析与实战案列&#xff0c;带你深入理解这三者的设计思想、使用场景以及闭…

SWUST数据结构下半期实验练习题

1068: 图的按录入顺序深度优先搜索 #include"iostream" using namespace std; #include"cstring" int visited[100]; char s[100]; int a[100][100]; int n; void dfs(int k,int n) {if(visited[k]0){visited[k]1;cout<<s[k];for(int i0;i<n;i){i…

机器学习 Day18 Support Vector Machine ——最优美的机器学习算法

1.问题导入&#xff1a; 2.SVM定义和一些最优化理论 2.1SVM中的定义 2.1.1 定义 SVM 定义&#xff1a;SVM&#xff08;Support Vector Machine&#xff0c;支持向量机&#xff09;核心是寻找超平面将样本分成两类且间隔最大 。它功能多样&#xff0c;可用于线性或非线性分类…

答题pk小程序道具卡的获取与应用

道具卡是答题PK小程序中必不可少的一项增加趣味性的辅助应用&#xff0c;那么道具卡是如何获取与应用的呢&#xff0c;接下来我们来揭晓答案&#xff1a; 一、道具卡的获取&#xff1a; 签到获取&#xff1a;在每日签到中签到不仅可获得当日的签到奖励积分&#xff0c;同时连…

leetcode3265. 统计近似相等数对 I-medium

1 题目&#xff1a;统计近似相等数对 I 官方标定难度&#xff1a;中 给你一个正整数数组 nums 。 如果我们执行以下操作 至多一次 可以让两个整数 x 和 y 相等&#xff0c;那么我们称这个数对是 近似相等 的&#xff1a; 选择 x 或者 y 之一&#xff0c;将这个数字中的两个…

【架构篇】代码组织结构设计

代码组织结构设计&#xff1a;模块化分层与高效协作实践 摘要 本文以Java项目为例&#xff0c;解析后端代码组织的标准化结构&#xff0c;涵盖模块划分原则、依赖管理策略及实际应用场景。通过模块化设计提升代码可维护性、团队协作效率及系统扩展能力。 一、模块化设计的核心…

日期数据渲染转换问题

今天在学习Springboot框架时&#xff0c;想做一个非常简单的增删改查巩固一下&#xff0c;结果在数据渲染上出现了一个小问题&#xff0c;如图数据库中的数据一切正常 但是在前端渲染时&#xff0c;是下面这个效果 这是因为数据库存储的日期类型数据在前端渲染时&#xff0c;没…

ubuntu18.04编译qt5.14.2源码

ubuntu18.04编译qt5.14.2源码 文章目录 ubuntu18.04编译qt5.14.2源码[toc]1 前言2 参考文档3 下载源码3.1 方法13.2 方法23.3 方法3 4 ubuntu编译qt源码4.1 环境准备4.2 设置交换分区大小4.3 编译源码4.4 添加环境变量4.5 验证编译结果4.6 编译帮助文档&#xff08;qch&#xf…

创建指定版本的vite项目

1、获取vite的版本号 npm view create-vite versions 注:4.4.1版本即对应着node16版本的项目 2、创建制定版本的vite项目 npm init vite<version>

iOS 初识RunLoop

iOS 初识RunLoop 文章目录 iOS 初识RunLoopRunLoop的概念RunLoop的功能RunLoop和线程的关系RunLoop的结构ModeObserverTimer 和 source小结 RunLoop的核心RunLoop的流程RunLoop的应用AutoreleasePool响应触控事件刷新界面常驻线程网络请求NSTimer 和 CADisplayLinkNSTimerGCDTi…

电子电路仿真实验教学平台重磅上线!——深圳航天科技创新研究院倾力打造,助力高校教学数字化转型

在传统电子电路课堂中&#xff0c;实验室的灯光总与高昂的成本、拥挤的设备、反复的耗材损耗相伴&#xff0c;而教师不得不面对这样的现实&#xff1a;有限的硬件资源束缚着教学深度&#xff0c;不可逆的实验风险制约着创新探索&#xff0c;固化的时空场景阻碍着个性化学习。当…

搭建一个WordPress网站需要多少成本

WordPress 最初可能只是一个简单的博客平台。但近年来&#xff0c;它不仅成为了最好的博客平台&#xff0c;还成为了一个全面的内容管理系统。白宫、jQuery、NGINX、《纽约时报》等企业都把 WordPress 作为自己的网上家园。 不过&#xff0c;它们只是其中的佼佼者。根据 Built…

Python数据可视化 - Pyecharts绘图示例

文章目录 一、Pyecharts简介及安装1. Pyecharts简介2. 安装Pyecharts 二、准备数据三、饼图示例1. 初始化选项配置2. 饼图相关设置3. 全局配置项3.1 标题配置项3.2 图例配置项3.3 提示框配置项3.4 工具箱配置项3.5 视觉映射配置项 4. 系列配置项4.1 标签选项配置4.2 图元样式配…

NC016NC017美光固态芯片NC101NC102

NC016NC017美光固态芯片NC101NC102 在存储技术的演进历程中&#xff0c;美光科技的NC016、NC017、NC101与NC102系列固态芯片&#xff0c;凭借其技术创新与市场适应性&#xff0c;成为行业关注的焦点。本文将从技术内核、产品性能、行业动向、应用场景及市场价值五个维度&#…

[Android] 青木扫描全能文档3.0,支持自动扫描功能

声明&#xff1a;根据许多帖友的反馈&#xff0c;我也根据重新实测得出结论&#xff1a;该app是提供一天的体验时间&#xff0c;后续还是采取收费才能使用功能的措施。因为现在市面上免费使用的扫描工具很少了&#xff0c;所以当初我初步测试感觉软件不错就发布了出来&#xff…

通俗解释Transformer在处理序列问题高效的原因(个人理解)

Transformer出现的背景 CNN 的全局关联缺陷卷积神经网络&#xff08;CNN&#xff09;通过多层堆叠扩大感受野&#xff0c;但在自然语言处理中存在本质局限&#xff1a; 局部操作的语义割裂&#xff1a;每个卷积核仅处理固定窗口&#xff08;如 3-5 词&#xff09;&#xff0c;…

区间带边权并查集,XY4060泄露的测试点

目录 一、题目 1、题目描述 2、输入输出 2.1输入 2.2输出 3、原题链接 二、解题报告 1、思路分析 2、复杂度 3、代码详解 一、题目 1、题目描述 2、输入输出 2.1输入 2.2输出 3、原题链接 码蹄集 二、解题报告 1、思路分析 关于带边权并查集&#xff1a;并查集&…