1.在IDEA中运行Nacos(001拓展)
1.1编辑配置信息
选择shell script(shell脚本)
script path(脚本路径)--- nacos目录下bin目录下的startup.cmd命令文件
CMD文件的专业名称叫链接器配置文件,是存放链接器的配置信息的,我们简称为命令文件
script options(脚本选项)需要执行的命令
点击运行启动nacos
服务注册中心 nacos启动成功
测试nacos http://localhost:8848/nacos
关闭nacos ctrl+c 需要等一会才能关闭
2.服务之间的调用
2.1提供方服务(sca-provider)注册
2.1.1.添加nacos服务的注册和发现依赖
根据官网提供:Nacos Spring 快速开始https://nacos.io/zh-cn/docs/quick-start-spring.html
<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>
2.1.2.创建并修改配置文件application.yml(或者application.properties),实现服务注册
server:
port: 8082 #服务端口
spring:
application:
name: sca-provider #服务名 不能重复 map集合k-value(value可以是一个集合)中的k 错误代码503服务不可用 检查nacos
cloud:
nacos: #服务
discovery: #服务的注册和发现
server-addr: localhost:8848 #nacos server
2.1.3创建启动类,并定义处理请求的控制层对象和方法:
package com.cy;
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.PathVariable;
import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication
public class ProviderApplication {
public static void main(String[] args) {
SpringApplication.run(ProviderApplication.class, args);
}
@RestController
public class providerController{
//动态赋值xml文件里的信息。配置默认值8080以防null时报错
@Value("${server.port:8080}")
private String server;
/* echo:回显的意思
rest:一种软件架构编码风格
访问:http://localhost:8081/provider/echo/nacos */
@GetMapping("/provider/echo/{msg}")
//兼容java8以下的版本 必须注明@PathVariable("msg")与请求路径的msg相同 变量则可以自定义
public String doRestEcho1(@PathVariable("msg") String msg1){
return server +"hello"+msg1;
}
}
}
控制层代码可以写在控制层里,但这里这是简单的一个入门案例我就直接写在启动类里了。
2.1.4测试提供方服务
注意:先启动Nacos在启动启动类,要不会报错
测试 http://localhost:8082/provider/echo/msa
证明我们的提供方服务创建成功
2.2消费方(sca-consumer)服务注册
2.2.1.添加依赖和提供方一样
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
</dependencies>
2.2.2.创建并修改配置文件application.yml(或者application.properties),实现服务注册
server:
port: 8090 #默认8090
spring:
application:
name: sca-consumer #假如做服务注册,必须写
cloud:
nacos:
discovery:
server-addr: localhost:8848 #nacos
2.2.3.创建消费方启动类并写入
package com.cy;
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.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import java.security.Provider;
@SpringBootApplication
public class ProviderApplication {
public static void main(String[] args) {
SpringApplication.run(ProviderApplication.class, args);
}
@RestController
public class providerController{
//动态赋值xml文件里的信息。配置默认值8080以防null时报错
@Value("${server.port:8080}")
private String server;
/*
echo:回显的意思
rest:一种软件架构编码风格
访问:http://localhost:8081/provider/echo/nacos
*/
@GetMapping("/provider/echo/{msg}")
//兼容java8以下的版本 必须注明@PathVariable("msg")与请求路径的msg相同 变量则可以自定义
public String doRestEcho1(@PathVariable("msg") String msg1){
return server +"hello"+msg1;
}
}
}
注意:先启动Nacos在启动启动类,要不会报错,可以看到现在消费方服务和提供方服务均已经启动。
测试消费方调用提供方
2.3负载均衡方法
如果一个提供方只能抗住10w的并发量,而消费方有100w的并发请求来调用提供方,这时则需要用到负载均衡的方法。所以至少得运行十个提供方
2.3.1 编辑ConsumerApplication启动类
思路 1.从注册中心获取服务实例 2.基于restTemplate进行服务实例调用
package com.cy;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
//服务消费方启动类
//当客户端向服务方发起请求时,服务消费方调用服务提供方的API进而获取服务提供方的数据
//例如我们访问一个订单模块数据;例如我的订单
//订单模块中还要呈现商品信息(成为提供方) 我调用consumer调用provider
@SpringBootApplication
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class, args);
}
/*
构建RestTemplate对象,并将此对象交给spring管理,
* 后续我们会通过此对象进行远程服务调用
*/
@Bean//也是交给spring容器去管理 跨进程使用该对象
//第三方整合用@Bean
//spring中有缓存 加了bean只需调用一次。不加就调用一次new一次对象
public RestTemplate restTemplate(){
return new RestTemplate();
}
@RestController
public class ConsumerController{
@Autowired//负载均衡客户端对象 调用
private LoadBalancerClient loadBalancerClient;
@Autowired
private RestTemplate restTemplate;
@Value("${spring.application.name}")
private String appName;
@GetMapping("/consumer/doRestEcho1")
public String doRestEcho1(){
//调用服务提供方API(不只是类和接口也包含请求路径)
//
String url="http://localhost:8081/provider/echo/"+appName;
return restTemplate.getForObject(url,String.class);
}
//负载均衡方式调用
@GetMapping("/consumer/doRestEcho2")
public String doRestEcho2(){
//1.从注册中心获取服务实例
//2.基于restTemplate进行服务实例调用
//服务实例instance
ServiceInstance instance = 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);
}
}
}
2.3.2 启动两个服务器
然后修改配置文件里的端口号。
此时已经开启了两个提供方服务器
测试:如果可以像我这样说明服务器已经在负载均衡了(默认为负载均衡中的轮询策略)
注意:
服务启动时会向nacos发送心跳包 五秒一次 ,十五秒没收到就标识你为 非健康状态
三十秒左右收不到心跳包 就确认你已经下线 就把你删掉服务,所以当我们关闭启动类时服务还暂存在Nacos中。
2.4代码优化
package com.cy;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
/**
* 服务消费方对象的启动类
* 业务描述:
* 当客户端(浏览器,手机app)向服务消费方发起请求时,
* 服务消费方调用服务提供方的api,进而获取服务提供方
* 的数据。
* 例如:
* 我们访问一个订单模块数据(例如我的订单),订单模块中
* 还要呈现商品信息。
*/
@SpringBootApplication
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class, args);
}
/**
* 构建RestTemplate对象,并将此对象交给spring管理,
* 后续我们会通过此对象进行远程服务调用
* @return
*/
@Bean
//@Bean("rt")
public RestTemplate restTemplate(){
return new RestTemplate();
}
@Bean
@LoadBalanced
public RestTemplate loadBalancerRestTemplate(){
return new RestTemplate();
}
@RestController
public class ConsumerController{
/**
* 负载均衡客户端对象
*/
@Autowired
private LoadBalancerClient loadBalancerClient;
@Autowired
private RestTemplate restTemplate;
@Autowired
private RestTemplate loadBalancerRestTemplate;
@Value("${spring.application.name}")
private String appName;
//http://ip:port/consumer/doRestEcho1
@GetMapping("/consumer/doRestEcho1")
public String doRestEcho1(){
System.out.println("==doRestEcho1()==");
//调用服务提供方API(http://ip:port/path)
//1.定义要调用的API
String url=
"http://localhost:8081/provider/echo/"+appName;
//2.谁去访问这个API? restTemplate;
return restTemplate
.getForObject(url,
String.class);
}
/**
* 负载均衡方式调用
* @return
*/
@GetMapping("/consumer/doRestEcho2")
public String doRestEcho2 (){
//1.从注册中心获取服务实例
ServiceInstance instance =
loadBalancerClient
.choose("sca-provider");
//2.基于RestTemplate进行服务实例调用
String ip=instance.getHost();//ip
int port=instance.getPort();//port
//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);
}
@GetMapping("/consumer/doRestEcho3")
public String doRestEcho3(){
//定义url
String url=
String.format("http://sca-provider/provider/echo/%s", appName);
//服务调用
return loadBalancerRestTemplate.getForObject(
url, String.class);
}
}
}
//browser->provider
//browser->consumer
//browser-(url)->consumer-(url)->provider
2.5 代码优化部分
3.面试分析
为什么要将服务注册到nacos?(为了更好的查找这些服务)
在Nacos中服务提供者是如何向Nacos注册中心(Registry)续约的?(5秒心跳)
对于Nacos服务来讲它是如何判定服务实例的状态?(检测心跳包,15,30)
服务启动时如何找到服务启动注册配置类?(NacosNamingService)
服务消费方是如何调用服务提供方的服务的?(RestTemplate)