SpringCloud系列入门
前言
微服务
微服务的核心思想是模块化,标准化,解耦合。
举例来说,比如一家公司,只有一个部门,这个部门管理一切技术、运营、财务、法务。。。你觉得能行么?放到spring里面来,古老的单体服务就像一家只有一个部门的公司,微服务要做的,就是把这些部门拆开,规定每个部门的责任范围,沟通标准等等。
本教程立足于以下版本约定:
- springboot2.4.1
- springcloud2020.0.1
springcloud
SpringCloud不是一个技术,而是一组技术。这一组技术结合起来总称SpringCloud,是微服务思想的implement。
一组技术
究竟有哪几大类呢?
- 服务注册中心。consul,nacos,zookeeper等
- RPC调用框架,feign,thrift等
- 消息中间件,rabbitMQ,rocketMQ,Kafaka,zeroMQ等
- 服务熔断降级,sentinel,hystrix等
- 消息总线,bus等
- 安全,SpringSecurity,shiro等
- 网关,gateway等
- 配置中心,nacos,config等
从最简单的微服务开始
最简单的微服务简单到你不敢想,其实大多数技术都是这样,原理都不难,主要是层层加码以后可能会遇到非常复杂的协调性问题。
父工程
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<spring-cloud.version>2020.0.1</spring-cloud.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.4.1</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>
</dependencies>
</dependencyManagement>
就光看这个依赖就知道简单的呀批。
服务提供者
最简单的服务提供者是啥呢?就是一个普通springboot服务,甚至都不一定要引入springcloud的任何组件,就像这样:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
这样:
server:
port: 8001
spring:
application:
name: service01
这样:
package yanyu;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @Desc
* @Author yanyu
* @Date 2021/2/20 5:01 下午
**/
@SpringBootApplication
@RestController
public class SApp01 {
public static void main(String[] args) {
SpringApplication.run(SApp01.class, args);
}
@GetMapping("/msg")
public String getMsg(){
return "hello!";
}
}
然后启动就行,超简单吧?
消费者
消费者也异常简单:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency> <!--
https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-actuator -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
<version>2.4.1</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
</dependencies>
其实openFeign完全不需要,从别的项目粘贴过来懒得删了
然后:
server:
port: 8080
base:
url: 'http://localhost:8001/msg'
然后:
package yanyu.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
/**
* @Desc
* @Author yanyu
* @Date 2021/2/20 5:18 下午
**/
@Configuration
public class RpcConfig {
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
最后:
package yanyu;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
/**
* @Desc
* @Author yanyu
* @Date 2021/2/20 5:17 下午
**/
@SpringBootApplication
@RestController
public class CApp {
public static void main(String[] args) {
SpringApplication.run(CApp.class, args);
}
@Resource
private RestTemplate restTemplate;
@Value("${base.url}")
String url;
@GetMapping("/")
public String say(){
return restTemplate.getForObject(url, String.class);
}
}
然后启动,访问消费者的跟路径,就能看到hello!了,是不是简单的令人发指?
分析
虽然简单,但蕴含着微服务最基本的理念:拆分,通信。把不同的功能做成不同的包,然后定义好接口后直接远程调用。在本例中restTemplate实际上执行了rpc的功能。
最重要的,无论微服务怎样千变万化,最终落地,也就是:
不同springboot项目之间通过各种网络协议相互通信、相互协作的过程。
问题
上面的案例虽然提供了一些很宝贵的思想,但还存在很多很关键的问题:
- 如果存在多个服务提供者,多个服务消费者,那么互相之间调用服务就会变成一个复杂的蜘蛛网,最终一定会变成无法管理的泥潭,怎么办?
- 多个机器环境运行了多个服务提供者Pn,如果所有请求都打到P0上,那剩下的实例呢?一个服务有难,n-1个服务围观?怎么让请求均衡的打到各个机器上?
- 请求太多,服务处理不过来了,就要宕机了,怎么办?继续任由请求打进来?
- 如果我有一些必须按时序传递的消息要在不同服务之间传递,该怎么做?
- n个服务怎么统一配置文件?难道手动一个一个改?好蠢啊?
- 这么多微服务怎么做安全管理?一个服务写一套?
不要急,后面会一点点解答这些问题。
服务注册中心版本
上节提到,如果存在多个服务提供者,多个服务消费者,那么互相之间调用服务就会变成一个复杂的蜘蛛网,最终一定会变成无法管理的泥潭。怎么解决?
其实现实早就给我们提供了答案。如果各位对固定电话有一定的了解,就会知道为了避免n个用户之间需要天文数字的电话线互相连接的问题,使用了一种叫做交换机的东西。所有的电话线都连到交换机,你要拨打哪里,交换机就给你转哪里。
服务注册中心就是微服务的“交换机”。
常用的服务注册中心有老牌的zookeeper,consul,也有新生代的nacos。由于nacos还想还没支持到springboot2.4.1,本教学就先使用consul。
安装consul
如果你有linux虚拟机,就在虚拟机上安装一个docker(题外话,我再一次推荐各位用docker学习各种技术,太好用了,省心省事),拉一个consul的image下来,运行起来就行。
# 拉镜像
docker pull docker.io/consul
# 跑起来
docker run -d --name dc -p 8500:8500 docker.io/consul
就装好了,在宿主机上访问即可,效果如下:
当然,虚拟机的防火墙要关掉。
把微服务注册到consul
生产者*2
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
</dependencies>
两个服务的yaml:
一号生产
# 01
server:
port: 8001
spring:
application:
name: consul-student-service
cloud:
consul:
port: 8500
host: {your host}
discovery:
service-name: ${spring.application.name}
二号生产一样的,只是把port换成8002。其中{your host}替换成你的consul地址。
然后是启动类:
package yanyu;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @Desc
* @Author yanyu
**/
@SpringBootApplication
@RestController
@EnableDiscoveryClient
public class SApp01 {
public static void main(String[] args) {
SpringApplication.run(SApp01.class, args);
}
@GetMapping("/msg")
public String getMsg(){
return "hello by 8001!";
}
}
二号服务只要把8001改成8002即可。
启动后可以在consul中发现这俩兄弟:
消费者
走流程,pom:
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
<version>2.4.1</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</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-consul-discovery</artifactId>
</dependency>
</dependencies>
yaml:
server:
port: 8080
base:
serviceName: consul-service
spring:
application:
name: consul-consumer
cloud:
consul:
host: {your host}
port: 8500
discovery:
service-name: ${spring.application.name}
# 消费者不是必须注册到consul中
register: false
由于这里涉及到多个生产实例,需要使用负载均衡,这个以后会讲,先用着就行:
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;
@Configuration
public class ApplicationContextConfig {
@Bean
@LoadBalanced // 负载均衡
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
启动类:
package yanyu;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
/**
* @Desc
* @Author yanyu
**/
@SpringBootApplication
@RestController
@EnableDiscoveryClient
public class CApp {
public static void main(String[] args) {
SpringApplication.run(CApp.class, args);
}
@Resource
private RestTemplate restTemplate;
@Value("${base.serviceName}")
String serviceName;
@GetMapping("/")
public String say(){
return restTemplate.getForObject("http://" + serviceName + "/msg", String.class);
}
}
启动起来,然后在浏览器或者curl工具或者postman啥的访问localhost:8080,
就会有下面两种情况:
很简单吧?
下一课会开始说openfeign,负载均衡和熔断机制,欢迎追更~
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/153522.html