什么是微服务
就是把大系统拆分为很多小系统,几个人负责一个服务这样 ,每个服务独立的开发、测试和上线, 代码冲突少 ,每次上线就回归测试自己的一个服务即可 ,只要向后兼容接口就行了,不需要跟别人等待和协调 。
SpringCloud Alibaba微服务解决方案
Spring Cloud Alibaba 是Spring Cloud的一个子项目
核心组件分析
服务注册与发现: 基于Spring Cloud 服务注册与发现标准,借助Nacos进行实现
分布式配置管理: 基于Nacos支持分布式系统中的外部化配置,配置更改时自动刷新。
解决方案架构设计
基于Spring Cloud Alibaba实现的微服务,解决方案设计架构如图所示:
项目
创建父工程模块
修改项目pom.xml文件内容,例如:
<!--统一依赖版本(spring boot,spring cloud,spring cloud alibaba)
注意,这里只做版本管理-->
<dependencyManagement>
<dependencies>
<!--Spring Boot-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.3.2.RELEASE</version>
<type>pom</type><!--允许scope的值为import时,type的值必须pom-->
<scope>import</scope> <!--这里的import类似java中的import-->
</dependency>
<!--Spring Cloud (Spring Cloud 工程依赖于spring boot),
spring cloud中定义的是一些微服务规范。-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Hoxton.SR9</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--Spring Cloud Alibaba (这套依赖是基于Spring Cloud规范,做了具体的落地实现)-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.2.6.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<!--定义公共依赖(lombok,test)-->
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<!--springboot 2.2以后版本默认单元测试使用的是junit5,
所以junit4以前的测试引擎不在需要-->
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<!--定义统一编译运行环境(jdk)-->
<build>
<plugins>
<!--定义maven的编译插件-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>8</source>
<target>8</target>
</configuration>
</plugin>
</plugins>
</build>
服务关系以及调用关系设计
nacos
不仅可以做注册中心,还可以作为配置中心
构建Nacos服务
初始化配置
打开表
source E:\app\nacos-server-1.4.2\nacos\conf\nacos-mysql.sql
打开/conf/application.properties里打开默认配置,并基于你当前环境配置要连接的数据库,连接数据库时使用的用户名和密码(假如前面有"#"要将其去掉):
服务注册与调用入门(重点)
两个共有的pom文件
<dependencies>
<!--Web服务-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--服务的注册和发现(我们要讲服务注册到nacos)-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
</dependencies>
创建并修改配置文件application.yml(或者application.properties),实现服务注册
server:
port: 8081
spring:
application:
name: sca-provider #进行服务注册必须配置服务名
cloud:
nacos:
discovery:
server-addr: localhost:8848
服务方
@RestController
public class ProviderController {
@Value("${server.port:8080}")
private String server;
//访问方式:
//1)浏览器中直接输入http://localhost:8081/provider/echo/tedu
//2)在sca-consumer服务中对这个服务进行访问
@GetMapping("/provider/echo/{msg}")
public String doRestEcho1(@PathVariable String msg) throws InterruptedException {
//Thread.sleep(5000);
return server+" say hello "+msg;
}
}
sca-consumer服务中的配置文件application.yml
server:
port: 8090
spring:
application:
name: sca-consumer #服务注册时,服务名必须配置
cloud:
nacos:
discovery:
server-addr: localhost:8848 #从哪里去查找服务
服务之间进行服务调用时,使用了什么API?(RestTemplate,用此对象之前要先创建这个对象并交给spring管理)
在sca-consumer启动类中添加如下方法,用于创建RestTemplate对象.
@Bean
public RestTemplate restTemplate(){//基于此对象实现远端服务调用
return new RestTemplate();
}
定义sca-consumer服务的消费端Controller,在此对象方法内部实现远端服务调用
/**
* 定义服务消费端Controller,在这个Controller对象
* 的方法中实现对远端服务sca-provider的调用
*/
@RestController
public class ConsumerController {
/**
* 从spring容器获取一个RestTemplate对象,
* 基于此对象实现远端服务调用
*/
@Autowired
private RestTemplate restTemplate;
/**
* 在此方法中通过一个RestTemplate对象调用远端sca-provider中的服务
* @return
* 访问此方法的url: http://localhost:8090/consumer/doRestEcho1
*/
@GetMapping("/consumer/doRestEcho1")
public String doRestEcho01(){
//1.定义要调用的远端服务的url
String url="http://localhost:8081/provider/echo/8090";
//2.基于restTemplate对象中的相关方法进行服务调用
return restTemplate.getForObject(url, String.class);
}
}
测试:
问题:
为什么要将服务注册到nacos?(为了更好的查找这些服务,一个是改变配置,不需要重新编译打包应用程序; 第二配置可以做到动态变更。)
在Nacos中服务提供者是如何向Nacos注册中心(Registry)续约的?(5秒心跳)
对于Nacos服务来讲它是如何判定服务实例的状态?(检测心跳包,15,30)
服务消费方是如何调用服务提供方的服务的?(RestTemplate)
Nacos如何检查服务状态?(通过心跳包实现,服务启动时会定时向nacos发送心跳包-BeatInfo)
服务之间进行服务调用时,使用了什么API?(RestTemplate,用此对象之前要先创建这个对象并交给spring管理)
实现Nacos服务注册需要添加什么依赖?(两个:web,discovery) 服务的注册和发现
Nacos如何检查服务状态?(通过心跳包实现,服务启动时会定时向nacos发送心跳包-BeatInfo)
服务负载均衡设计及实现(重点)
消费者访问多个服务实例
LoadBalancerClient应用
这里多个实例并发提供服务的方式为负载均衡,这里的负载均衡实现默认是因为Nacos集成了Ribbon来实现的,Ribbon配合RestTemplate,可以非常容易的实现服务之间的访问。Ribbon是Spring Cloud核心组件之一,它提供的最重要的功能就是客户端的负载均衡(客户端可以采用一定算法,例如轮询访问,访问服务端实例信息),这个功能可以让我们轻松地将面向服务的REST模版请求自动转换成客户端负载均衡方式的服务调用。
/**
* 负载均衡客户端对象,基于此对象可以获取nacos中的服务实例,
* 并且通过负载均衡算法从所有实例中取一个实例。
Ribbon 是什么?
Netflix公司提供的负载均衡客户端,一般应用于服务的消费方法
LoadBalancerClient对象可以从nacos中基于服务名获取服务实例,然后在工程中基于特点算法实现负载均衡方式的调用
*/
@Autowired
private LoadBalancerClient loadBalancerClient;
@Value("${spring.application.name:sca-consumer}")
private String appName;
@GetMapping("/consumer/doRestEcho2")
public String doRestEcho2(){
//从nacos获取服务实例(这里的choose方法内置了负载均衡算法)
ServiceInstance instance = //"sca-provider"为nacos服务列表中的一个服务名
loadBalancerClient.choose("sca-provider");
String ip=instance.getHost();
int port=instance.getPort();
//String url="http://"+ip+":"+port+"/provider/echo/"+appName;
String url=String.format("http://%s:%s/provider/echo/%s",ip,port,appName);
//执行远端服务调用
return restTemplate.getForObject(url,
String.class//远端url对应的方法的返回值类型(响应数据类型)
);
}
@LoadBalanced
@LoadBalanced注解是属于Spring,而不是Ribbon的,Spring在初始化容器的时候,如果检测到Bean被@LoadBalanced注解,Spring会为其设置LoadBalancerInterceptor的拦截器。
当使用RestTemplate进行远程服务调用时,假如需要负载均衡,还可以在RestTemplate对象构建时,使用@LoadBalanced对构建RestTemplate的方法进行修饰,例如在ConsumerApplication中构建名字为loadBalancedRestTemplate的RestTemplate对象:
@Bean
@LoadBalanced
public RestTemplate loadBalancedRestTemplate(){
return new RestTemplate();
}
@Autowired
private RestTemplate loadBalancedRestTemplate;
@GetMapping("/consumer/doRestEcho3")
public String doRestEcho3(){
//定义远程调用的url
String url=String.format("http://%s/provider/echo/%s","sca-provider",appName);
//执行远端服务调用
return loadBalancedRestTemplate.getForObject(url,
String.class//远端url对应的方法的返回值类型(响应数据类型)
);
}
小节面试:
-
@Bean注解的作用?(一般用于配置类内部,描述相关方法,用于告诉spring此方法的返回值要交给spring管理,bean的名字默认为方法名,假如需要指定名字可以@Bean(“bean的名字”),最多的应用场景是整合第三方的资源-对象)
-
@Autowired注解的作用?(此注解用于描述属性,构造方法,set方法等,用于告诉spring框架,按找一定的规则为属性进行DI操作,默认按属性,方法参数类型查找对应的对象,假如只找到一个,则直接注入,类型多个时还会按照属性名或方法参数名进行值的注入,假如名字也不同,就出报错.)
-
Nacos中的负责均衡底层是如何实现的?(通过Ribbon实现,Ribbon中定义了一些负载均衡算法,然后基于这些算法从服务实例中获取一个实例为消费方法提供服务)
-
Ribbon 是什么?(Netflix公司提供的负载均衡客户端,一般应用于服务的消费方法)
-
Ribbon 可以解决什么问题? (基于负载均衡策略进行服务调用, 所有策略都会实现IRule接口)
-
Ribbon 内置的负载策略都有哪些?(8种,可以通过查看IRule接口的实现类进行分析)
-
@LoadBalanced的作用是什么?(描述RestTemplate对象,用于告诉Spring框架,在使用RestTempalte进行服务调用时,这个调用过程会被一个拦截器进行拦截,然后在拦截器内部,启动负载均衡策略。)
-
我们可以自己定义负载均衡策略吗?(可以,基于IRule接口进行策略定义,也可以参考NacosRule进行实现)