news 2026/5/25 18:30:36

不用写几行代码的springcloud(一)—— 什么是SpringCloud、从零搭建一个微服务工程

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
不用写几行代码的springcloud(一)—— 什么是SpringCloud、从零搭建一个微服务工程

零、标题为什么是不用写几行代码的springcloud?

因为Springcloud的几乎不需要在springboot项目基础上增加什么新的代码

一、为什么会诞生springcloud?

为什么会诞生springcloud,因为springboot微服务变多了,就需要管理问题。

面试题springboot和springcloud的区别?

怎么会有这么zhizhang的面试题,springboot是用来构建微服务项目的,springcloud是用来治理微服务的,先有springboot再有springcloud。

二、微服务架构的4个核心问题

  1. 服务很多,客户端该怎么访问?
  2. 服务之间是如何通信的?
  3. 这么多服务,如何治理?
  4. 服务挂了怎么办?

解决方案:springcloud不是一门技术,也不是一个框架,而是一个生态,或者说一套理论,或者理解成一个接口。围绕着这个生态有很多解决方案,或者说接口的实现。下面介绍三套解决方案,各有优缺点。

解决方案(一):spring cloud NetFlix

一站式解决方案(就是上面四个问题都能解决),用的很多,因为比较成熟,虽然已经停止维护了

(1)api网关:zuul组件

(2)Feign

(3)Eureka

(4)Hystrix

解决方案(二):Apache Dubbo Zookeeper

不是一站式的(就是只能解决上面四个问题里的一部分,其他部分要靠整合其他组件去解决),半自动化

(1)api网关:没有,所以要整合第三方组件,比如zuul

(2)Dubbo(Dubbo的定义是一款RPC框架,所以Dubbo主要用来解决上面第二个核心问题)

(3)Zookeeper也没有,需要整合第三方组件,比如Hystrix

(4)Spring cloud Alibaba 一站式解决方案,2019年孵化出来

解决方案(三)【最常用:Spring cloud Alibaba 一站式解决方案,2019年孵化出来

(1)服务注册与发现:nacos

(2)流量控制与熔断:sentinel

(3)消息队列:RocketMQ

(4)分布式通信:Dubbo。feign是HTTP架构,dubbo是RPC架构

(5)Seata :转账交易的事务一致性

解决方案(其他):

三、手把手教你从零搭建一个微服务项目

new一个干净的maven项目作为总项目,把原有的src文件夹删了

为什么new一个maven项目而不是new一个springboot项目呢?

因为springboot项目会自带pom.xml包,不利于我们从0进行包的管理。maven项目的pom.xml里没有包。

然后进行总pom文件的配置,以及整个微服务依赖的管理。

在父pom文件里,继承父pom文件VS在<dependencyManagement>里引入

就是继承类和实现接口的关系,继承只能继承一个类,实现可以实现多个接口。同理,子pom文件只能继承一个父pom文件,但是可以在<dependencyManagement>引入多个pom文件。

PS:注意,<dependencyManagement>只在父pom文件里用。你想一下,如果在子pom文件里用<dependencyManagement>引入别的pom文件,版本号就别人写死的了,那我们怎么进行不同模块之间依赖版本的统一??

<?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"> <!--xmlns: 指定这份pom.xml文件的行业标准来自Apache公司--> <!--xmlns:xsi:指定--> <!--xsi:schemaLocation 指定参考模版位置--> <modelVersion>4.0.0</modelVersion> <!--maven遵循的版本是4.0.0,同上面http://maven.apache.org/pom/4.0.0--> <groupId>org.example</groupId> <artifactId>spring-cloud-study</artifactId> <version>1.0-SNAPSHOT</version> <modules> <module>spring-cloud-model</module> <module>spring-cloud-provider-dept-8001</module> </modules> <!--打包方式:pom--> <packaging>pom</packaging> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <junit.version>4.12</junit.version> <log4j.version>1.2.17</log4j.version> <lombok.version>1.18.12</lombok.version> </properties> <!--这是一个总工程--> <!--dependencyManagement只是管理,标签里面包含的依赖并不会被导入,你刷新一下maven就能看出来--> <dependencyManagement> <dependencies> <!--springcloud的依赖文件, 注意这里是把一整个文件给引入进来了, 引入这个以后,子pom文件就可以用这个文件里的依赖了--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>2021.0.3</version> <type>pom</type> <scope>import</scope> </dependency> <!--springboot的依赖文件, 注意这里是把一整个文件给引入进来了, 引入这个以后,子pom文件就可以用这个文件里的依赖了--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>2.7.14</version> <type>pom</type> <scope>import</scope> </dependency> <!--数据库 版本要和mysql的版本匹配起来,mysql是5开头的话这个也要以5开头,如果是8开头。。--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.10</version> </dependency> <!--springboot的starter--> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.3.2</version> </dependency> <!--junit单元测试--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>${junit.version}</version> </dependency> <!--日志(SL4j是一个接口,可以对接log4j也可以对接logback--> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>${log4j.version}</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> <version>1.3.2</version> </dependency> <!--lombok:之前总结说以插件的方式使用,但是安装插件以后还是没法用@Data等注释 所以导入一下依赖--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>${lombok.version}</version> </dependency> </dependencies> </dependencyManagement> <!--静态资源过滤--> <build> <resources> <resource> <directory>src/main/java</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> <include>**/*.yml</include> </includes> <filtering>false</filtering> </resource> <resource> <directory>src/main/resources</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> <include>**/*.yml</include> </includes> <filtering>false</filtering> </resource> </resources> </build> </project>

PS: <denpendencyMangement>里只是管理依赖,并不会导入。实践一下,你刷新一下maven,并不会导入任何依赖。

如果后面需要静态资源过滤的话,再补充下面的配置

<!--静态资源过滤--> <build> <resources> <resource> <directory>src/main/java</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> <include>**/*.yml</include> </includes> <filtering>false</filtering> </resource> <resource> <directory>src/main/resources</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> <include>**/*.yml</include> </includes> <filtering>false</filtering> </resource> </resources> </build>

3.1 数据库表

3.2 新建spring-cloud-model模块

然后新建微服务的第一个module,专门用于存放实体类

在大的pom文件里,就会出现<modules>标签

然后配置这个模块的pom文件。

需要什么依赖,先在父pom文件的<dependencyManagment>里导入并指定版本号,然后再来子pom文件的<dependencies>里导入,子pom里不需要指定版本号。这样做的原因是,如果有4个子模块,都用到了junit依赖,如果各自在各自的pom文件里指定版本号的话,可能在一个项目中出现4个不一样版本的junit依赖,所以我们要在父pom里进行版本的统一管理。

删掉test文件夹

然后在main文件夹里新建“com.kuang.springcloud.pojo”这样一个目录,在pojo下新建Dept.java实体类

package com.kuang.springcloud.pojo; import javafx.beans.NamedArg; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.Accessors; import java.io.Serializable; @Data @NoArgsConstructor @Accessors(chain = true) //实现链式编程 public class Dept implements Serializable { //所有实体类首先要实现序列化!! private Long deptNo; private String deptName; private String db_source; //因为deptNo是自动生成的 public Dept(String deptName){ this.deptName = deptName; } }

3.3 新建服务提供者spring-cloud-provider-8001模块

1、写pom文件。这是第二个模块了,因为能用到第一个模块,所以在pom文件的<dependencies>里把第一个模块当做依赖引入。然后其他用到的依赖就正常引入,不做展示了。

<?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"> <parent> <artifactId>spring-cloud-study</artifactId> <groupId>org.example</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>spring-cloud-provider-dept-8001</artifactId> <dependencies> <!--① 因为要用到这个微服务的实体类--> <dependency> <!--groupId是maven坐标的其中一个,在我们new project的时候指定的, 那时候默认是org.example,如果你有公司了,可以写公司名--> <groupId>org.example</groupId> <artifactId>spring-cloud-model</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <!--②一些基本的依赖--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> </dependency> <!--③springboot相关--> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-test</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--跟Tomcat没有区别,另一个应用启动器--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jetty</artifactId> </dependency> <!--④热部署工具--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> </dependency> </dependencies> </project>

2、然后写服务提供者模块的配置文件,在该模块的src/resources下新建一个application.yml

server: port: 8001 #mybatis配置 mybatis: # 别名 type-aliases-package: com.kuang.springcloud.pojo # sql.xml的位置 mapper-locations: classpath:mapper/*.xml configuration: # 开启二级缓存。虽然默认是开启的,但还要显式开启一下 cache-enabled: true spring: application: # 给应用起个名字,springcloud服务的注册与发现,用的都是这个名字 name: springcloud-provider datasource: driver-class-name: org.gjt.mm.mysql.Driver url: jdbc:mysql://localhost:3306/db01?useUnicode=true&characterEncoding=utf8 username: root password: 123456

3、新建一个dao层,然后写XxxMapper.java接口(用到的实体类是前面那个模块的,spring-cloud-model模块的,我们通过pom文件引入了),写完mapper接口写xml文件。

package com.kuang.springcloud.dao; import com.kuang.springcloud.pojo.Dept; import org.apache.ibatis.annotations.Mapper; import java.util.List; @Mapper public interface DeptMapper { Boolean add(Dept dept); Dept queryOne(int deptno); List<Dept> list(); }
<?xml version="1.0" encoding="UTF8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.kuang.springcloud.dao.DeptMapper"> <insert id="add" parameterType="com.kuang.springcloud.pojo.Dept"> insert into dept(deptname,db_source) values (#{deptName},#{db_source}) </insert> <select id="queryOne" resultType="com.kuang.springcloud.pojo.Dept"> select * from dept where deptno = #{deptno} </select> <select id="list" resultType="com.kuang.springcloud.pojo.Dept"> select * from dept </select> </mapper>

4、然后新建service层,写service层。

package com.kuang.springcloud.service; import com.kuang.springcloud.pojo.Dept; import org.apache.ibatis.annotations.Mapper; import org.springframework.stereotype.Service; import java.util.List; @Service public interface IDeptService { Boolean add(Dept dept); Dept queryOne(int deptno); List<Dept> list(); }
package com.kuang.springcloud.service.impl; import com.kuang.springcloud.dao.DeptMapper; import com.kuang.springcloud.pojo.Dept; import com.kuang.springcloud.service.IDeptService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; @Service public class DeptServiceImpl implements IDeptService { @Autowired DeptMapper deptMapper; @Override public Boolean add(Dept dept) { return deptMapper.add(dept); } @Override public Dept queryOne(int deptno) { return deptMapper.queryOne(deptno); } @Override public List<Dept> list() { return deptMapper.list(); } }

5、然后新建controller层,写controller。

package com.kuang.springcloud.controller; import com.kuang.springcloud.pojo.Dept; import com.kuang.springcloud.service.impl.DeptServiceImpl; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*; import java.util.List; @RestController @RequestMapping("dept") public class DeptController { @Autowired DeptServiceImpl deptService; @PostMapping("/add") public Boolean add(@RequestBody Dept dept) { return deptService.add(dept); } @GetMapping("/get/{deptno}") public Dept queryOne(@PathVariable int deptno) { return deptService.queryOne(deptno); } @GetMapping("/list") public List<Dept> list() { return deptService.list(); } }

6、然后写主启动类。

package com.kuang.springcloud; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class DeptApplication { public static void main(String[] args) { SpringApplication.run(DeptApplication.class,args); } }

然后运行

3.4 新建服务消费者spring-cloud-consumer-dept-80模块

package com.kuang.springcloud.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.client.RestTemplate; @Configuration public class ConfigBean { @Bean public RestTemplate getRestTemplate(){ return new RestTemplate(); } }

消费者的消费行为没有自己的service层和dao层,直接在controller层调用别人的。but,我们这里只是演示,所以功能比较单一,因为实际上一个模块肯定既是消费者又是生产者,肯定有自己的service层和dao层的,所以前面写的是“消费者的消费行为没有自己的service层和dao层”而不是整个消费者

PS:“只有在学习的时候才分消费者和生产者,实际中每个微服务都兼具生产者和消费者,既要给其他微服务提供接口,又要调用其他微服务。”

package com.kuang.springcloud.controller; import com.kuang.springcloud.pojo.Dept; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; import java.util.List; @RestController public class DeptConsumerController { @Autowired private RestTemplate restTemplate; @RequestMapping("/consumer/dept/add") public Boolean add(@RequestBody Dept dept){ //post请求就用postForObject,get请求就用getForObject return restTemplate.postForObject("http://localhost:8001/dept/add",dept,Boolean.class); } @RequestMapping("/consumer/dept/get/{id}") public Dept get(@PathVariable("id") Long id){ return restTemplate.getForObject("http://localhost:8001/dept/get/"+id,Dept.class); } @RequestMapping("/consumer/dept/list") public List<Dept> list(){ return restTemplate.getForObject("http://localhost:8001/dept/list",List.class); } }

主启动类.java

package com.kuang.springcloud; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class DeptConsumerApplication { public static void main(String[] args) { SpringApplication.run(DeptConsumerApplication.class,args); } }
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"> <parent> <artifactId>spring-cloud-study</artifactId> <groupId>org.example</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>spring-cloud-comsumer-dept-80</artifactId> <dependencies> <!--用到了生产者的模块,就在这引入--> <dependency> <groupId>org.example</groupId> <artifactId>spring-cloud-provider-dept-8001</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--热部署--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> </dependency> </dependencies> </project>
application.yml
server: port: 80 # 因为消费者模块在pom里引入了生产者模块: # <dependency> # <groupId>org.example</groupId> # <artifactId>spring-cloud-provider-dept-8001</artifactId> # <version>1.0-SNAPSHOT</version> # </dependency> # 而生产者模块用到了数据库,如果不在消费者这里配置数据库,会报找不到datasource的错误 spring: datasource: driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://localhost:3306/db01?useUnicode=true&characterEncoding=utf8 username: root password: 123456

同时开启生产者和消费者的服务,消费者发起一个新增数据的请求

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

Java序列化机制深度解析

前言 在现代软件开发中&#xff0c;Java序列化机制深度解析是一个非常重要的技术点。本文将从原理到实践&#xff0c;带你深入理解这一技术&#xff0c;并通过完整的代码示例帮助你快速掌握核心知识点。 核心概念 基本原理 Java序列化机制深度解析的核心在于理解其底层机制。以…

作者头像 李华
网站建设 2026/5/25 18:29:11

数据结构--2:ArrayList与顺序表

顺序表顺序表是一种线性数据结构&#xff0c;使用一段物理地址(内存)连续的存储单元&#xff08;通常为数组&#xff09;&#xff0c;依次存储数据元素&#xff0c;并在此基础上封装了增、删、改、查等操作&#xff1b;而普通数组只提供下标访问和长度属性。在 Java 中&#xf…

作者头像 李华
网站建设 2026/5/25 18:26:04

浏览器下载太慢?3步配置Motrix扩展,让下载速度提升300%!

浏览器下载太慢&#xff1f;3步配置Motrix扩展&#xff0c;让下载速度提升300%&#xff01; 【免费下载链接】motrix-webextension A browser extension for the Motrix Download Manager and its forks 项目地址: https://gitcode.com/gh_mirrors/mo/motrix-webextension …

作者头像 李华
网站建设 2026/5/25 18:25:12

校园周边美食探索及分享平台的设计与实现(源码+毕设)

校园周边美食探索及分享平台 摘要&#xff1a; 美食一直是与人们日常生活息息相关的产业。传统的电话订餐或者到店消费已经不能适应市场发展的需求。随着网络的迅速崛起&#xff0c;互联网日益成为提供信息的最佳俱渠道和逐步走向传统的流通领域&#xff0c;传统的美食业进而也…

作者头像 李华
网站建设 2026/5/25 18:25:11

深度学习序列建模(二)—— 长期依赖与梯度爆炸/消失(四十四)

1. 定位导航 第 43 篇我们看到 BPTT 通过乘积链反向传播——这就埋下了 RNN 训练困难的根源。 Goodfellow 的尖锐警示: {Bengio1994ITNN} 的实验表明,当增加需要捕获的依赖关系的跨度,基于梯度的优化变得越来越困难,SGD 在长度仅为 10 或 20 的序列上成功训练传统 RNN 的…

作者头像 李华