目录

1.项目背景

1.1 项目架构设计(单父工程 + 多子模块)

1.2 业务场景

2.搭建 Eureka 服务注册中心(servicecenter1)

2.1 新建项目

2.2 在项目clouddemo2中新建模块servercenter1

2.3 修改模块servercenter1下的内容

2.3.1 配置 pom.xml 依赖

2.3.2 配置 application.properties

2.3.3 启动类编写

2.3.4 启动测试

3.搭建数据服务生产者(dbservice)

3.1 数据库前置准备

3.2 配置 pom.xml 依赖

3.3 配置 application.properties

3.4 核心业务代码编写

3.4.1 实体类:Classes(与 t_classes 表一一对应)

3.4.2 DAO 层:DBDao(MyBatis 数据访问层)

3.4.3 Controller 层:DBController(对外提供 HTTP 接口)

3.4.4 启动类编写

3.5 启动测试

4.搭建用户服务消费者(users)

4.1 配置 pom.xml 依赖

4.2 配置 application.properties

4.3 核心业务代码编写

4.3.1 核心配置类:RestTemplateConfig(解决循环依赖核心)

4.3.2 实体类:Classes(与生产者完全一致)

4.3.3 Controller 层:UserController(远程调用 + 对外接口)

4.3.4 启动类编写

5.整体运行与全流程测试

5.1 严格启动顺序(避免注册失败)

5.2 验证服务注册

5.3 验证远程调用与数据返回

5.4 验证 Ribbon 客户端负载均衡


1.项目背景

本文将实战实现 Eureka 服务注册与发现、生产者(dbservice)操作 MySQL 数据库、消费者(users)远程 RPC 调用,同时整合 Ribbon 实现客户端负载均衡。

1.1 项目架构设计(单父工程 + 多子模块)

采用企业标准的父工程聚合子模块模式,职责划分清晰,便于维护和扩展:

springcloud-demo(父工程)
├─ servicecenter1(Eureka注册中心,端口8088):管理所有服务实例的注册、发现与状态监控
├─ dbservice(数据服务生产者,端口9091):操作MySQL数据库,提供标准化数据查询接口
└─ users(用户服务消费者,端口8025):远程调用dbservice,对外提供统一业务访问入口

1.2 业务场景

实现班级信息查询基础业务:

  • dbservice 连接 MySQL,查询t_classes表数据,暴露/querydata接口;
  • users 通过RestTemplate(整合 Ribbon)以服务名远程调用dbservice
  • 所有服务均注册到servicecenter1,实现服务解耦与动态发现。

2.搭建 Eureka 服务注册中心(servicecenter1)

作为微服务架构的核心枢纽,Eureka 注册中心负责接收所有服务的注册请求,为消费者提供服务实例发现能力,是微服务通信的基础。

2.1 新建项目

2.2 在项目clouddemo2中新建模块servercenter1

2.3 修改模块servercenter1下的内容

2.3.1 配置 pom.xml 依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.18</version>
        <relativePath/>
    </parent>
    <groupId>com.hy</groupId>
    <artifactId>servercenter1</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>servercenter1</name>
    <description>Eureka服务注册中心</description>

    <properties>
        <java.version>17</java.version>
        <spring-cloud.version>2021.0.8</spring-cloud.version>
    </properties>

    <dependencies>
        <!-- Spring Boot核心依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <!-- 单元测试依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- Eureka Server核心依赖 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
    </dependencies>

    <!-- Spring Cloud版本管理,强制统一版本,避免依赖冲突 -->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

2.3.2 配置 application.properties

核心配置 Eureka 服务端参数,关闭自身注册与发现(注册中心无需将自己注册到服务列表),指定服务端口和注册地址:

# 服务名称,唯一标识注册中心
spring.application.name=servercenter1
# Eureka服务端口
server.port=8088
# Eureka实例主机名
eureka.instance.hostname=localhost

# 关闭注册中心自身注册到Eureka(核心配置)
eureka.client.register-with-eureka=false
# 关闭注册中心从Eureka发现其他服务(核心配置)
eureka.client.fetch-registry=false
# Eureka注册地址,供其他服务注册使用
eureka.client.service-url.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka
# 关闭Eureka自我保护机制(开发环境建议开启,生产环境关闭)
eureka.server.enable-self-preservation=false

2.3.3 启动类编写

添加@EnableEurekaServer注解标记为 Eureka 服务端,配合@SpringBootApplication开启 Spring Boot 自动配置,代码极简:

package com.hy.servercenter1;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

/**
 * Eureka服务注册中心启动类
 * @EnableEurekaServer 开启Eureka服务端功能
 */
@EnableEurekaServer
@SpringBootApplication
public class Servercenter1Application {

    public static void main(String[] args) {
        SpringApplication.run(Servercenter1Application.class, args);
    }

}

2.3.4 启动测试

运行启动类,无报错后访问 Eureka 控制台:http://localhost:8088,页面显示No instances available说明注册中心启动成功,等待生产者和消费者注册。

3.搭建数据服务生产者(dbservice)

dbservice作为服务生产者,是微服务的数据层服务,负责与 MySQL 数据库交互,提供标准化的 HTTP 数据接口,注册到 Eureka 后供消费者远程调用,是数据交互的核心节点。

3.1 数据库前置准备

在 MySQL 中创建数据库和表,插入测试数据

-- 创建表 --
CREATE TABLE t_classes (
    cid INT PRIMARY KEY AUTO_INCREMENT,
    cname VARCHAR(20) NOT NULL,
    cphone VARCHAR(200)
);

-- 删除数据库表,用于先前如果创建好的表 --
DROP TABLE t_classes

-- 插入数据 --
INSERT INTO t_classes(cname,cphone) VALUES("鸿蒙班","13800013800");
INSERT INTO t_classes(cname,cphone) VALUES("Java班","13700013700");
INSERT INTO t_classes(cname,cphone) VALUES("仓颉班","13600013600");

-- 查询表 --
SELECT * FROM t_classes

3.2 配置 pom.xml 依赖

引入 Eureka Client、Spring Web、MyBatis、MySQL 驱动、Ribbon 核心依赖,所有版本均由 Spring Cloud 2021.0.8 统一管理,无版本冲突:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.18</version>
        <relativePath/>
    </parent>
    <groupId>com.hy</groupId>
    <artifactId>dbservice</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>dbservice</name>
    <description>数据服务生产者,操作MySQL数据库</description>

    <properties>
        <java.version>17</java.version>
        <spring-cloud.version>2021.0.8</spring-cloud.version>
        <mybatis.version>2.2.2</mybatis.version>
        <mysql.connector.version>8.0.33</mysql.connector.version>
    </properties>

    <dependencies>
        <!-- Spring Web:提供HTTP接口能力 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- Eureka Client:注册到Eureka注册中心 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <!-- Ribbon:客户端负载均衡 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
        </dependency>
        <!-- MyBatis整合Spring Boot -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>${mybatis.version}</version>
        </dependency>
        <!-- MySQL驱动:适配MySQL8.0+ -->
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <version>${mysql.connector.version}</version>
            <scope>runtime</scope>
        </dependency>
        <!-- 测试依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <!-- Spring Cloud版本管理 -->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

3.3 配置 application.properties

整合Eureka 注册数据库连接MyBatis三大核心配置,一步到位,无冗余参数:

# 服务名称,消费者通过该名称调用(核心,必须与调用名一致)
spring.application.name=dbservice
# 服务端口
server.port=9091
# 注册到Eureka的地址(与注册中心保持一致)
eureka.client.service-url.defaultZone=http://127.0.0.1:8088/eureka
# 服务实例过期时间,加快服务剔除
eureka.instance.lease-expiration-duration-in-seconds=30

# MySQL数据库连接配置(适配8.0+)
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/mysql2026
spring.datasource.username=root
spring.datasource.password=yourpassword
# 连接池大小
spring.datasource.hikari.maximum-pool-size=10

# MyBatis配置
# 实体类包扫描
mybatis.type-aliases-package=com.hy.dbservice.model
# 开启DAO层日志,方便调试SQL
logging.level.com.hy.dbservice.dao=debug

3.4 核心业务代码编写

遵循MVC 分层思想,按实体类 ->DAO 层 ->Controller 层编写代码,结构清晰,符合企业开发规范。

3.4.1 实体类:Classes(与 t_classes 表一一对应)

package com.hy.dbservice.model;

/**
 * 班级实体类,映射t_classes表
 */
public class Classes {
    private int cid; // 班级ID
    private String cname; // 班级名称
    private String cphone; // 班级联系电话

    // Getter和Setter方法
    public int getCid() {
        return cid;
    }

    public void setCid(int cid) {
        this.cid = cid;
    }

    public String getCname() {
        return cname;
    }

    public void setCname(String cname) {
        this.cname = cname;
    }

    public String getCphone() {
        return cphone;
    }

    public void setCphone(String cphone) {
        this.cphone = cphone;
    }
}

3.4.2 DAO 层:DBDao(MyBatis 数据访问层)

使用注解式 MyBatis实现 SQL 查询,无需编写 XML 映射文件,简化开发,适合简单查询场景,添加@Mapper注解让 Spring 自动扫描并创建实现类:

package com.hy.dbservice.dao;

import com.hy.dbservice.model.Classes;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

import java.util.List;

/**
 * 数据访问层,操作t_classes表
 */
@Mapper
public interface DBDao {
    // 查询所有班级信息
    @Select("select * from t_classes")
    List<Classes> queryClassesInfo();
}

3.4.3 Controller 层:DBController(对外提供 HTTP 接口)

暴露/querydata接口作为消费者调用入口,注入 DAO 层对象实现数据库查询,返回 JSON 格式数据:

package com.hy.dbservice.controller;

import com.hy.dbservice.dao.DBDao;
import com.hy.dbservice.model.Classes;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

/**
 * 数据服务控制器,提供数据查询接口
 * @RestController 标记为REST风格控制器,返回JSON数据
 */
@RestController
public class DBController {

    // 自动注入DAO层对象
    @Autowired
    private DBDao dbDao;

    // 对外提供的班级信息查询接口
    @RequestMapping("/querydata")
    public List<Classes> queryData() {
        System.out.println("DBController is queryData start... ");
        // 调用DAO层查询数据库
        List<Classes> lists = dbDao.queryClassesInfo();
        return lists;
    }
}

3.4.4 启动类编写

添加@EnableDiscoveryClient注解开启 Eureka 客户端能力,让服务自动注册到 Eureka 注册中心:

package com.hy.dbservice;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

/**
 * 数据服务生产者启动类
 * @EnableDiscoveryClient 开启Eureka客户端,实现服务注册与发现
 */
@EnableDiscoveryClient
@SpringBootApplication
public class DbserviceApplication {

    public static void main(String[] args) {
        SpringApplication.run(DbserviceApplication.class, args);
    }

}

3.5 启动测试

  • 确保 Eureka 注册中心已启动;
  • 运行DbserviceApplication,无报错即启动成功;
  • 访问 Eureka 控制台http://localhost:8088,可看到DBSERVICE服务状态为UP,说明注册成功;
  • 直接访问接口http://localhost:9091/querydata,页面返回 JSON 格式的班级数据,说明数据库交互和接口正常。

4.搭建用户服务消费者(users)

users作为服务消费者,是微服务的应用层服务,不直接操作数据库,通过RestTemplate服务名方式远程调用dbservice的接口,对外提供统一的业务访问入口,实现服务解耦和业务分层。

4.1 配置 pom.xml 依赖

引入 Eureka Client、Spring Web、Ribbon 核心依赖,与生产者版本保持一致,保证微服务架构依赖统一:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.18</version>
        <relativePath/>
    </parent>
    <groupId>com.hy</groupId>
    <artifactId>users</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>users</name>
    <description>用户服务消费者,远程调用数据服务</description>

    <properties>
        <java.version>17</java.version>
        <spring-cloud.version>2021.0.8</spring-cloud.version>
    </properties>

    <dependencies>
        <!-- Spring Web:提供HTTP接口 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- Eureka Client:注册到Eureka并发现服务 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <!-- Ribbon:开启客户端负载均衡 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
        </dependency>
        <!-- 测试依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <!-- Spring Cloud版本管理 -->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

4.2 配置 application.properties

简洁配置服务名、端口和 Eureka 注册地址,与注册中心、生产者保持配置一致:

# 服务名称
spring.application.name=users
# 服务端口
server.port=8025
# 注册到Eureka的地址
eureka.client.service-url.defaultZone=http://127.0.0.1:8088/eureka
# 开启服务发现
eureka.client.fetch-registry=true

4.3 核心业务代码编写

4.3.1 核心配置类:RestTemplateConfig(解决循环依赖核心)

RestTemplate的 Bean 定义抽离为独立配置类,彻底解决循环依赖,也是企业开发中Bean 配置与业务代码解耦的标准写法:

package com.hy.users.config;

import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

/**
 * 全局Bean配置类,避免Bean循环依赖
 */
@Configuration // 标记为配置类,Spring会扫描并执行内部@Bean方法
public class RestTemplateConfig {

    // 定义RestTemplate Bean,与UserController解耦
    @Bean
    @LoadBalanced // 保留负载均衡功能
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

4.3.2 实体类:Classes(与生产者完全一致)

消费者需要创建与生产者字段名、类型完全一致的实体类,用于接收远程调用返回的 JSON 数据并自动封装:

package com.hy.users.model;

/**
 * 班级实体类,与dbservice中的实体类保持一致
 */
public class Classes {
    private int cid;
    private String cname;
    private String cphone;

    // Getter和Setter方法
    public int getCid() {
        return cid;
    }

    public void setCid(int cid) {
        this.cid = cid;
    }

    public String getCname() {
        return cname;
    }

    public void setCname(String cname) {
        this.cname = cname;
    }

    public String getCphone() {
        return cphone;
    }

    public void setCphone(String cphone) {
        this.cphone = cphone;
    }
}

4.3.3 Controller 层:UserController(远程调用 + 对外接口)

核心实现RestTemplate 配置(添加@LoadBalanced开启负载均衡)和远程服务调用,对外暴露/query统一访问接口,通过服务名 dbservice替代 IP + 端口,实现服务解耦:

package com.hy.users.controller;

import com.hy.users.model.Classes;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.util.List;

/**
 * 用户服务控制器,远程调用dbservice并对外提供接口
 */
@RestController
public class UserController {

    // 注入配置好的RestTemplate
    @Autowired
    private RestTemplate restTemplate;

    /**
     * 配置RestTemplate Bean
     * @LoadBalanced 开启客户端负载均衡,支持通过服务名调用
     */
    @Bean
    @LoadBalanced
    public RestTemplate getRestTemplate() {
        return new RestTemplate();
    }

    /**
     * 对外提供的统一查询接口,内部远程调用dbservice
     * @return 班级信息列表
     */
    @RequestMapping("/query")
    public List<Classes> loadData() {
        System.out.println("UserController is loadData start...");
        // 核心:通过服务名dbservice远程调用,由Eureka发现服务,Ribbon实现负载均衡
        List<Classes> lists = this.restTemplate.getForObject("http://dbservice/querydata", List.class);
        return lists;
    }
}

4.3.4 启动类编写

添加@EnableDiscoveryClient注解,开启服务注册与发现能力,让消费者能从 Eureka 中发现dbservice服务实例:

package com.hy.users;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

/**
 * 用户服务消费者启动类
 */
@EnableDiscoveryClient
@SpringBootApplication
public class UsersApplication {

    public static void main(String[] args) {
        SpringApplication.run(UsersApplication.class, args);
    }

}

5.整体运行与全流程测试

5.1 严格启动顺序(避免注册失败)

微服务启动需遵循依赖顺序,确保注册中心先启动,再启动生产者,最后启动消费者:

  • 第一步:启动 Eureka 注册中心 servercenter1(8088)
  • 第二步:启动数据服务生产者 dbservice(9091)
  • 第三步:启动用户服务消费者 users(8025)

5.2 验证服务注册

访问 Eureka 控制台http://localhost:8088,可看到DBSERVICEUSERS两个服务均为UP状态,说明所有服务成功注册到 Eureka,服务治理生效。

5.3 验证远程调用与数据返回

访问消费者对外暴露的统一接口:http://localhost:8025/query,页面将以JSON 格式返回 MySQL 中的班级信息,效果如下:

同时观察控制台日志:

  • 消费者users控制台:打印UserController is loadData start...
  • 生产者dbservice控制台:打印DBController is queryData start... + DAO 层 SQL 执行日志

说明微服务远程 RPC 调用成功,实现了从消费者接口 -> 生产者接口 -> MySQL 数据库的全流程数据交互。

5.4 验证 Ribbon 客户端负载均衡

dbservice开启多实例部署,验证 Ribbon 的轮询负载均衡能力,步骤如下:

  • 打开dbservice的 IDEA 运行配置,勾选Allow multiple instances(允许多实例运行);
  • 修改dbserviceapplication.propertiesserver.port为 9092,再次启动dbservice
  • 访问 Eureka 控制台,可看到dbservice2 个实例(9091/9092),均为 UP 状态;
  • 多次刷新消费者接口http://localhost:8025/query,生产者 9091 和 9092 的控制台会交替打印日志,说明 Ribbon 负载均衡生效,请求在多个生产者实例间轮询分发。
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐