学习参考博客:
一、SpringCloud与SpringCloud Alibaba的区别
二、为什么要选择SpringCloud Alibaba
参考文章 : 为什么选择SpringCloud Alibaba
SpringCloud中的组件:
- 用于服务注册与发现的 Eureka;
- 用于服务限流降级的 Hystrix(官方都推荐用别的);
- 网关 Zuul(现在还是用Gateway)。
以上组件都已经封版停止更新了,不更新维护了,可见,如果继续使用,后期难免会出现一些问题,为了项目的质量有所保障,需要采取新的解决方案,SpringCloud就是一个很好的选择,未来的开发过程中,我们难免会使用到阿里的相关生态服务,所以,选择SpringCloud Alibaba在这方面的交互就会更好一些,当然,选择它的原因也不仅在此,SpringCloud Alibaba还提供了许多强大的功能,方便使用者使用和开发。
三、版本依赖查询
在使用SpringCloud Alibaba前,我们应该了解相关的依赖,以避免不必要的版本冲突。
四、Nacos的启动
五、nacos的注册与发现
nacos就是微服务架构中服务注册中心以及统一配置中心,用来替换掉原来的注册中心(eureka,consul)以及config组件。
(一)环境搭建
在管理依赖的时候,今后的项目可能会使用到SpringBoot+SpringCloud+SpringCloud Alibaba,我们可以通过添加版本依赖来指定下载文件的位置。
<dependencyManagement>
<!--个人觉得在开发过程管理中,如果想要结合springcloud、springcloudAlibaba、springboot,可以把他们三个的依赖都放进来管理,
个人觉得 如果这里管理了版本号,那么集成这个包的就会自动的指定版本了-->
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-boot-alibaba-dependencies</artifactId>
<version>${spring.cloud.alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--SpringCloud下载仓库-->
<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>
(二)将服务注册到nacos
<!--无需引入spring-boot-starter-actuator-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version>${spring.cloud.alibaba.version}</version>
</dependency>
(三)简单的Demo
这里简单创建一个控制器来模拟数据。
CustomerController
@RestController
@Slf4j
public class CustomerController {
@Value("${server.port}")
private int port;
@GetMapping("/customer/find")
public Map<String,Object> find(@RequestParam("id") String id){
Map<String,Object> map=new HashMap<>();
log.info("进入商品服务,当前接受的id为"+id);
map.put("status",true);
map.put("msg","当前服务调用成功,查询的id为"+id+"当前处理的端口为"+port);
return map;
}
}
application.properties
server:
port: 8001
spring:
application:
name: nacosclient8001 #指定服务名称
cloud:
nacos:
server-addr: localhost:8848 #指定nacos地址(注册到的地方:nacos)
discovery:
server-addr: ${spring.cloud.nacos.server-addr} #指定注册的地址
management:
endpoints:
web:
exposure:
include: "*" #暴露所有的web节点
启动成功,可以在服务列表中成功看到该服务了
六、服务之间的消费
nacos作为客户端的感知非常快,如果两个服务,其中有一个服务宕机了,那么列表中这个服务就会立即消失,就感知不到这个服务了。
这里创建了一个CustomerService9002和一个UserServie9001,项目配置过程省略:
目录结构如下:
CustomerService9002
UserServie9001
那么如何从一个服务去调用另外一个服务呢:
我们可以使用以下方法:
(一)restTemplate
缺点:指定了url,在项目的开发中,不可能通过指定url,这样无法实现服务的负载均衡。
//这种方法是写死的,不太好,就没法实现服务的负载均衡
RestTemplate restTemplate = new RestTemplate();
String forObject=restTemplate.getForObject("http://localhost:9002/customer/find?id="+id,String.class);
(二)restTemplate+ribbon负载均衡客户端
缺点:过于繁琐
UserController:
//2.通过restTemplate+ribbon负载均衡客户端 DiscoveryClient LoadBalancedClient 注解形式
@Autowired
private DiscoveryClient discoveryClient;//拉取所有的服务节点
@Autowired
private LoadBalancerClient loadBalancerClient;
@GetMapping("/user/find")
public Map<String, Object> getProductById(String id){
//2.1 拉去服务列表(DiscoveryClient)
List<ServiceInstance> CustomerService = discoveryClient.getInstances("customerservice9002");//服务名(ServiceId)是nacos注册的服务名
for (ServiceInstance serviceInstance :CustomerService) {
log.info("服务地址:",serviceInstance.getUri());
}
//2.2 服务列表(列表里面存放着请求头+端口)拿到了,接下来就可以自己写负载均衡算法了 LoadBalance默认使用的是轮询
ServiceInstance loadBalancerclient = loadBalancerClient.choose("customerservice9002");
System.out.println("拿到的uri为"+loadBalancerclient.getUri());
//2.3 现在都拿到uri了,那么下一步就可以拼接url了,使用restTemplate就可以了
String object1=restTemplate.getForObject(loadBalancerclient.getUri()+"/customer/find?id="+id,String.class);
(三)使用注解@LoadBalanced
RestTemplateConfig:
@Configuration
public class RestTemplateConfig {
@Bean
@LoadBalanced //创建一个具有负载均衡的RestTemplate对象
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
UserController:
@Resource
private RestTemplate restTemplate; //引入自定义负载均衡的restTemplate
@GetMapping("/user/find")
public Map<String, Object> getProductById(String id){
// 3. 使用注解 方便了许多
String forObject = restTemplate.getForObject("http://customerservice9002/customer/find?id=" + id, String.class); //nacos中的服务名+方法名+参数
log.info("返回到的信息为:"+forObject);
}
(四)openFeign调用(最优)
导入依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>2.2.3.RELEASE</version>
</dependency>
定义CustomerClient:
@FeignClient("customerservice9002") //指定nacos上的服务名
public interface CustomerClient {
@GetMapping("/customer/find")
public Map<String, Object> find(@RequestParam("id") String id);
}
UserController:
@GetMapping("/user/find")
public Map<String, Object> getProductById(String id){
Map<String, Object> map = customerClient.find(id);
log.info("返回的信息值"+map);
return map;
}
总结:通过以上四种方式能够实现服务间的消费,最好的是使用openFeign调用, 这三种方式也会有很多的缺点,比如讲地址耦合在代码之中,地址如果改了,参数名如果改了,那么维护的成本将会非常高。
七、使用nacos作为配置中心
试想一下,我们的项目实际开发过程中可能会有多个环境,而且微服务中,必然会有许多配置文件,那么,我们由什么方法对这些配置文件实现统一的管理呢,nacos就为我们提供了这样的一个功能,我们可以把配置文件交给nacos来管理,下面来实践一下。
(一)导入依赖
<!--引入nacos config 依赖 (把配置文件交给nacos管理)-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
<version>${spring.cloud.alibaba.version}</version>
</dependency>
(二)bootstrap.yaml(拉取远程配置文件)
nacos拉取配置文件时,可以指定命名空间、分组、文件名、文件类型,这样就能实现文件的精准定位。
spring:
cloud:
nacos:
server-addr: localhost:8848
config:
#${prefix}-${spring.profiles.active}.${file-extension}
#${spring.application.name}-${spring.profiles.active}-${file-extension}
server-addr: ${spring.cloud.nacos.server-addr}
namespace: 2672ff8c-0226-466c-8a1b-038ee73a78d7 #从哪个命名空间拉去 一定是命名空间的id
group: userService #从命名空间下的哪个组拉去:默认:DEFAULT_GROUP
file-extension: yaml #拉取的配置文件类型是什么 不能简写 只能是yaml
application:
name: userservice9001
(三) 在nacos上进行配置
这里配置了一个user.name,这里在控制器中定义一个方法进行远程配置文件的读取
至此,实践全部完成了,那么如果项目开发过程中需要更改配置文件,需要加入注解才能实现动态的更新,不然在nacos中进行更新配置时,Controller方法在调用时,并不会动态的更新,如果想要实现动态更新,需要加入@RefreshScope注解,这样在nacos进行更新配置文件的时候,方法也能够立即更新,读出的值也能够随着配置文件动态变化了。
nacos还可以通过添加命名空间、添加分组、克隆配置、导入配置、新建配置等操作实现配置的多方面管理。