SpringCloud和nacos实现一个基础的微服务
随着业务复杂度的提升,单体应用暴露出越来越多的问题,微服务架构已成为主流选择。Spring Cloud 作为 Java 领域微服务的翘楚,提供了全家桶式的解决方案。Spring Cloud Alibaba 的核心组件 Nacos 提供了 服务发现、配置管理,有了这两个瑞士军刀就可以从零开始搭建一个包含服务注册发现、服务间调用、API 网关的基础微服务系统。
这里不讨论 “为什么要用 nacos” 或者“为什么用 nacos 不用 Eureka” 之类的话题,如果想知道为什么不用或者为什么要用可以去 Google 或者 百度 搜索一下会有很多文章告诉我们这些,我再说一遍就老生长谈了,我这里只是我想通过我的理解给大家一个最快实现微服务的这样一个场景。
这篇文章的前提是你需要会使用 Docker ,了解 微服务,会使用 SpringBoot
技术栈说明
- JDK 17
- Maven
3.9.6
- IDEA 或者你可以换成 eclipse 、 vscode?
- SpringBoot
3.4.7
- Spring Cloud
2024.0.1
- Spring Cloud Alibaba
2023.0.3.3
- Nacos
v2.4.3
- Docker Compose
先搞一个 Docker Compose 文件 docker-compose.yml
来创建一个 Nacos 的服务,我这里只做了单机的Derby模式,Derby也是一个数据库一个完全用java编写的数据库。有兴趣的可以了解一下
services:
experiment-nacos:
image: nacos/nacos-server:v2.4.3
container_name: "experiment-nacos-standalone"
environment:
- PREFER_HOST_MODE=hostname
- MODE=standalone
- NACOS_AUTH_IDENTITY_KEY=serverIdentity
- NACOS_AUTH_IDENTITY_VALUE=security
- NACOS_AUTH_ENABLE=true
- NACOS_AUTH_TOKEN=f58d900b73ea2a7227ae1c69dc88b41adf277c7a3852505fdfad6c25b715ab8b
volumes:
- ./nacos/standalone-logs:/home/nacos/logs
- ./nacos/data:/home/nacos/data
ports:
- 48848:8848
- 49848:9848
# 定义自定义网络 (推荐做法,便于服务间通信)
networks:
experiment_network:
driver: bridge
在当前目录下打开一个终端,执行 docker-compose up -d
这时候会将这个 nacos 服务启动成功,就会像下面这个一样
E:\test-java-project\runbrick-experiment-project\experiment-docker> docker-compose.exe up -d
[+] Running 1/1
✔ Container experiment-nacos-standalone Started 0.9s
好了这时候打卡浏览器输入 localhost:48848/nacos
,第一次打开nacos的界面登录时候的账号 nacos
,密码随便输入,但是你输入后之后的密码就是你这次输入的密码了。
如果这些都准备好了,nacos 这里就先放放了,我们开始开发一个超级简单的微服务
我先放出我最后写好的微服务项目结构树,
按照这个目录我们先创建一个父级目录 cloud-experiment-project
,我这里爆红是因为我已经有这个目录了
在生成的目录中会有一个 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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.runbrick</groupId>
<artifactId>runbrick-experiment-project</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<packaging>pom</packaging>
<artifactId>cloud-experiment-project</artifactId>
<modules>
<module>cloud-gateway-project</module>
<module>cloud-system-project</module>
<module>cloud-infra-project</module>
</modules>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring.boot.version>3.4.7</spring.boot.version>
<spring-cloud.version>2024.0.1</spring-cloud.version>
<spring.cloud.alibaba.version>2023.0.3.3</spring.cloud.alibaba.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>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring.cloud.alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
这个目录我们不需要里面的 src 目录,直接删掉。同时在这个目录下创建 cloud-gateway-project、cloud-infra-project、cloud-system-project 三个 module
分别在这3个module中的pom.xml 填入下面内容
cloud-gateway-project
<?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>com.runbrick</groupId>
<artifactId>cloud-experiment-project</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>cloud-gateway-project</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>cloud-gateway-project</name>
<description>cloud-gateway-project</description>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway-mvc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- Registry 注册中心相关 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- Config 配置中心相关 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
cloud-infra-project
<?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>com.runbrick</groupId>
<artifactId>cloud-experiment-project</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>cloud-infra-project</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>cloud-infra-project</name>
<description>cloud-infra-project</description>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- Registry 注册中心相关 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- Config 配置中心相关 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
cloud-system-project
<?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>com.runbrick</groupId>
<artifactId>cloud-experiment-project</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>cloud-system-project</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>cloud-system-project</name>
<description>cloud-system-project</description>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- Registry 注册中心相关 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- Config 配置中心相关 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
配置中最主要的内容就是
<!-- Registry 注册中心相关 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- Config 配置中心相关 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
和网关服务的
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway-mvc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
创建每个服务的 application.yml
文件
cloud-gateway-project
spring:
application:
name: cloud-gateway-project
main:
allow-circular-references: true # 允许循环依赖,因为项目是三层架构,无法避免这个情况。
config:
import:
- optional:nacos:${spring.application.name}.yml # 加载【Nacos】的配置
cloud:
gateway:
mvc:
routes:
- id: cloud-system-project
uri: lb://cloud-system-project
predicates:
- Path=/cloud-system/**
filters:
- StripPrefix=1
nacos:
server-addr: 127.0.0.1:48848
username: nacos
password: nacos
discovery:
namespace: public
group: DEFAULT_GROUP
metadata:
version: 1.0.0
config:
namespace: public
group: DEFAULT_GROUP
cloud-infra-project
spring:
application:
name: cloud-infra-project
main:
allow-circular-references: true # 允许循环依赖,因为项目是三层架构,无法避免这个情况。
config:
import:
- optional:nacos:${spring.application.name}.yml # 加载【Nacos】的配置
cloud:
nacos:
server-addr: 127.0.0.1:48848
username: nacos
password: nacos
discovery:
namespace: public
group: DEFAULT_GROUP
metadata:
version: 1.0.0
config:
namespace: public
group: DEFAULT_GROUP
server:
port: 8082
cloud-system-project
spring:
application:
name: cloud-system-project
main:
allow-circular-references: true # 允许循环依赖,因为项目是三层架构,无法避免这个情况。
config:
import:
- optional:nacos:${spring.application.name}.yml # 加载【Nacos】的配置
cloud:
nacos:
server-addr: 127.0.0.1:48848
username: nacos
password: nacos
discovery:
namespace: public
group: DEFAULT_GROUP
metadata:
version: 1.0.0
config:
namespace: public
group: DEFAULT_GROUP
server:
port: 8081
创建每个服务的SpringBootApplication文件
cloud-gateway-project
package com.runbrick.gateway;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class CloudGatewayProjectApplication {
public static void main(String[] args) {
SpringApplication.run(CloudGatewayProjectApplication.class, args);
}
}
cloud-infra-project
package com.runbrick.infra;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class CloudInfraProjectApplication {
public static void main(String[] args) {
SpringApplication.run(CloudInfraProjectApplication.class, args);
}
}
cloud-system-project
package com.runbrick.system;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class CloudSystemProjectApplication {
public static void main(String[] args) {
SpringApplication.run(CloudSystemProjectApplication.class, args);
}
}
启动每个服务的 application 就可以看到 nacos 界面里面有这三个服务注册了
这时候可以去给 cloud-infra-project 和 cloud-system-project 创建一套测试接口了
cloud-infra-project
package com.runbrick.infra.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/user")
public class UserController {
@RequestMapping("/info")
public String info() {
return "这是 user 服务";
}
}
cloud-system-project
package com.runbrick.system.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("dict")
public class DictController {
/**
* 获取字典数据
* @return 字典数据
*/
@GetMapping("info")
public String info() {
return "这是字典服务";
}
}
这时候重启一下服务,使用 IDEA 自带的http request 功能来测试一下服务是否成功
记得端口号是 gateway 服务配置的 port 。如果想调用 infra 服务自己去修改下 gateway 的 routes 。按照我写的 cloud-system-project 服务自己抄一个试试
cloud:
gateway:
mvc:
routes:
- id: cloud-system-project
uri: lb://cloud-system-project
predicates:
- Path=/cloud-system/**
filters:
- StripPrefix=1
- id: cloud-infra-project
.... 自己补全测试一下