spring cloud

spring cloud

Spring Cloud是微服务架构思想的一个具体实现,它为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理、服务发、断路器,智能路由、微代理、控制总线等)。
Spring Cloud 基于 Spring Boot 框架,它不重复造轮子,而是将第三方实现的微服务应用的一些模块集成进去。准确的说,Spring Cloud 是一个容器。

最简单的 Spring Cloud 微服务架构包括服务发现和服务提供者(即一个大型系统拆分出来的子模块),最极端的微服务可以做到一个方法就是一个服务,一个方法就是一个项目。在一个系统中,服务怎么拆分,要具体问题具体分析,也取决于系统的并发性、高可用性等因素。

微服务间消息传递

微服务是一种软件开发架构,它将一个大型应用程序拆分为一系列小型、独立的服务。每个服务都可以独立开发、部署和扩展,并通过轻量级的通信机制进行交互。

应用开发

  • common模块中包含服务提供者和服务消费者共享的内容
  • provider模块是服务的提供者,用于通过SpringMVC的控制器提供访问接口

服务提供者

@RestController
@RequestMapping("/users")
public class HelloController {
	@GetMapping("/hello")
	public String sayHello(@RequestParam String username) {
		if (username == null || username.trim().length() < 1)
		username = "MicroService";
		return "Provider: hello " + username + "!";
	}
}

服务消费者

服务消费者通过http协议访问服务提供者,可以使用JDK的URL或者使用HttpClient之类的工具,但是直接使用工具比较繁琐,所以使用SpringBoot提供的RestTemplate进行访问。
在主类或者当前应用的配置类上声明RestTemplate。

@SpringBootApplication
public class ConsumerApplication {
	public static void main(String[] args) {
	SpringApplication.run(ConsumerApplication.class, args);
}
@Bean
public RestTemplate restTemplate() {
		return new RestTemplate();
	}
}

核心配置,主要修改一下访问端口号,因为应用的默认端口都是8080,会有端口号冲突的问题

server.port=7081

定义控制器实现访问服务提供者

@RestController
@RequestMapping("/consumer")
public class ConsumerController {
	@Autowired
	private RestTemplate restTemplate;
	@GetMapping("/{name}")
	public String test(@PathVariable String name){
		//RestTemplate针对RESTful中的get/post/delete/put分别提供了对应的方法
		String res =restTemplate.getForObject("http://localhost:7080/users/hello?username="+name, String.class);
		return res;
	}
}

测试验证
在这里插入图片描述

Nacos服务治理

Nacos即Naming and Configuration Service是一个用于动态服务发现、配置管理和服务元数据的开源平台。
在这里插入图片描述

应用开发步骤

服务提供者

需要添加额外的依赖,也就是Nacos的客户端

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacosdiscovery</artifactId>
</dependency>

添加配置application.properties

# 配置当前应用名称,默认情况下向nacos注册的服务名称就是这个名称
spring.application.name=service-provider
# Nacos 服务发现与注册配置,其中子属性 server-addr 指定 Nacos 服务器主机和端口
spring.cloud.nacos.discovery.server-addr=localhost:8848
# 注册到 nacos 的指定 namespace,默认为 public
spring.cloud.nacos.discovery.namespace=public
# 应用服务 WEB 访问端口
server.port=6080

添加JavaConfig配置或者在主类上添加注解以启用Nacos客户端

@EnableDiscoveryClient
@Configuration
public class NacosDiscoveryConfiguration {
}

定义服务提供者

@RestController
@RequestMapping("/users")
public class HelloController {
	@GetMapping("/hello")
	public String sayHello(@RequestParam String username) {
		if (username == null || username.trim().length() < 1)
		username = "MicroService";
		return "Provider: hello " + username + "!";
	}
}

服务消费者

依赖

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacosdiscovery</artifactId>
</dependency>

添加核心配置application.properties

server.port=6081
spring.application.name=service-consumer
# Nacos 服务发现与注册配置,其中子属性 server-addr 指定 Nacos 服务器主机和端口
spring.cloud.nacos.discovery.server-addr=localhost:8848
# 注册到 nacos 的指定 namespace,默认为 public
spring.cloud.nacos.discovery.namespace=public

添加配置类或者在主类上添加注解启用Nacos客户端

@EnableDiscoveryClient
@SpringBootApplication
public class Consumer1Application {
	public static void main(String[] args) {
		SpringApplication.run(Consumer1Application.class, args);
	}
@Bean
public RestTemplate restTemplate() {
		return new RestTemplate();
	}
}

定义服务消费者

@RestController
@RequestMapping("/consumer")
public class ConsumerController {
	@Autowired
	private RestTemplate restTemplate;
	@Autowired
	private DiscoveryClient discoveryClient;
	@GetMapping("/{name}")
	public String test(@PathVariable String name){
		//服务的名称对应的是服务提供者的application.properties中的配置
		spring.application.name=service-provider
		List<ServiceInstance> instances =
		discoveryClient.getInstances("service-provider"); //因为一个服务可以运行在多个节点上或者使用多个进程
		//自定义负载均衡策略实现从多个服务提供者实例中选择一个
		Random r=new Random();
		ServiceInstance instance =
		instances.get(r.nextInt(instances.size()));
		String res =restTemplate.getForObject(instance.getUri()+"/users/hello?username=" +name,String.class);
		return res;
	}
}

验证测试

在这里插入图片描述

引入负载均衡

在消费方引入负载均衡机制,同时简化获取服务提供者信息的流程
Spring Cloud引入组件LoadBalance实现负载均衡

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacosdiscovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>

properties配置

spring.application.name=service-consumer
# Nacos 服务发现与注册配置,其中子属性 server-addr 指定 Nacos 服务器主机和端口
spring.cloud.nacos.discovery.server-addr=localhost:8848
# 注册到 nacos 的指定 namespace,默认为 public
spring.cloud.nacos.discovery.namespace=public
server.port=6082

主类上添加对应的注解

@EnableDiscoveryClient
@SpringBootApplication
public class Consumer2Application {
public static void main(String[] args) {
	SpringApplication.run(Consumer2Application.class, args);
}
@LoadBalanced
@Bean
public RestTemplate restTemplate() {
		return new RestTemplate();
	}
}

定义对应的控制器,需要访问服务提供者

@RestController
@RequestMapping("/consumer")
public class ConsumerController {
@Autowired
private RestTemplate restTemplate;
@GetMapping("/{name}")
public String test(@PathVariable String name){
//使用LB后具体的URL地址中使用服务提供者的名称来替代原始的主机名和端口号
String res = restTemplate.getForObject("http://serviceprovider/users/hello?username=" + name, String.class);
return res;
}
}

验证测试
在这里插入图片描述

缓存配置

使用LB从Nacos获取服务的注册信息,可以在本地进行缓存。添加配置即可

spring.cloud.loadbalancer.cache.enabled=true #启用本地缓存,可以根据实际情况权衡
spring.cloud.loadbalancer.cache.capacity=1000 #设置缓存空间大小
spring.cloud.loadbalancer.cache.ttl=20 #缓存的存活时间,单位为s

订阅更新

缓存有可能和远程的注册信息不一致,所以引入长连接的订阅实现Nacos的主动通知更改

spring.cloud.nacos.discovery.watch.enabled=true

引入OpenFeign

添加依赖:

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacosdiscovery</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-openfeign</artifactId>
</dependency>

定义配置:

server.port=6083
# Nacos帮助文档: https://nacos.io/zh-cn/docs/concepts.html
spring.application.name=service-consumer
# Nacos 服务发现与注册配置,其中子属性 server-addr 指定 Nacos 服务器主机和端口
spring.cloud.nacos.discovery.server-addr=localhost:8848
# 注册到 nacos 的指定 namespace,默认为 public
spring.cloud.nacos.discovery.namespace=public

在主类或者配置类上添加注解以支持OpenClient应用

@EnableFeignClients // 激活 @FeignClient
@EnableDiscoveryClient
@SpringBootApplication
public class Consumer3Application {
	public static void main(String[] args) {
		SpringApplication.run(Consumer3Application.class, args);
	}
}

定义http伪客户端接口

@FeignClient("service-provider") // 指向服务提供者应用
public interface ProviderClient {
	@GetMapping("/users/hello")
	public String sayHello(@RequestParam("username") String username);
}

定义控制器,通过feign接口调用远程的服务提供者

@RestController
@RequestMapping("/consumer")
public class ConsumerController {
	@Autowired
	private ProviderClient providerClient;
	@GetMapping("/{name}")
	public String test(@PathVariable String name){
		String res = providerClient.sayHello(name);
		return res;
	}
}

测试
在这里插入图片描述

负载均衡策略配置

LB中提供了三种负载均衡策略,同时提供接口允许用户自定义扩展
在这里插入图片描述
1、定义配置类

public class FeignClientConfiguration {
	@Bean
	public ReactorLoadBalancer
	reactorServiceInstanceLoadBalancer(ObjectProvider
	serviceInstanceListSuppliers, Environment environment) {
		String name =
		environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
		return new RandomLoadBalancer(serviceInstanceListSuppliers, name);
	}
}

2、可以全局或者局部配置使用设置的负载均衡策略

@EnableFeignClients(defaultConfiguration = FeignClientConfiguration.class)
@EnableDiscoveryClient
@SpringBootApplication
public class Consumer3Application {
	public static void main(String[] args) {
		SpringApplication.run(Consumer3Application.class, args);
	}
}

局部配置

@FeignClient(value="service-provider",configuration =
FeignClientConfiguration.class)
public interface ProviderClient {
	@GetMapping("/users/hello")
	public String sayHello(@RequestParam("username") String username);
}

失败重试机制配置

如果通过使用OpenFeign访问远程的服务提供者,则可以配置由于网络、连接、读取等问题出现访问失败时,自动执行重试处理
1、首先定义配置

public class FeignClientConfiguration {
@Bean
public Retryer retryer(){
	return new Retryer.Default(100, 1000, 2);
//表示每间隔100ms,最大间隔1000ms重试一次,最大重试次数是1,因为第三个参数包含了第一次请求
	}
}

2、可以在注解中进行全局配置和局部配置
全局配置

@EnableFeignClients(defaultConfiguration = FeignClientConfiguration.class)
@EnableDiscoveryClient
@SpringBootApplication
public class Consumer3Application {
	public static void main(String[] args) {
		SpringApplication.run(Consumer3Application.class, args);
	}
}

局部配置

@FeignClient(value="service-provider",configuration =
FeignClientConfiguration.class)
public interface ProviderClient {
	@GetMapping("/users/hello")
	public String sayHello(@RequestParam("username") String username);
}

服务降级配置

在使用注册中心时,OpenFeign作为服务间通信的组件,它本身集成了负载均衡能力、错误重试、日志、服务熔断等机制,同时也能够支持点对点的通信方式,让开发者感觉更像是调用本地接口,而不是发起HTTP请求
具体的服务降级是依赖Sentinel组件实现的,所以需要添加Sentinel依赖
1、添加依赖

<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

2、开启服务熔断配置application.properties

feign.circuitbreaker.enabled=true

3、定义对应的Fallback Factory实现

@Component
public class ProviderClientFallbackFactory implements
FallbackFactory<ProviderClient> {
	@Override
	public ProviderClient create(Throwable cause) {
		return new ProviderClient() {
			@Override
			public String sayHello(String username) {
				return cause.getMessage();
			}
		};
	}
}

4、配置使用Fallback降级处理

@FeignClient(value="service-provider",fallbackFactory =
ProviderClientFallbackFactory.class)
public interface ProviderClient {
	@GetMapping("/users/hello")
	public String sayHello(@RequestParam("username") String username);
}

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

Nacos配置管理

将应用中的所有配置信息进行统一管理,同时当修改配置时会自动通知对应的微服务进行热加载。
Nacos在微服务集群中充当了配置管理中心的用途。
需求例如有个配置 yan.date.format=yyyy-MM-dd
配置中心的思路是:

  • 首先把项目中各种配置全部都放到一个集中的地方进行统一管理,并提供一套标准的接口。
  • 当各个服务需要获取配置的时候,就来配置中心的接口拉取自己的配置。
  • 当配置中心中的各种参数有更新的时候,也能通知到各个服务实时的过来同步最新的信息,使之动态更新。

1、添加依赖

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacosconfig</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
<version>3.1.5</version>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacosdiscovery</artifactId>
</dependency>

2、新增一个配置文件bootstrap.properties或者yaml格式都可以

spring.cloud.nacos.config.server-addr=localhost:8848 服务配置中心的配置
spring.cloud.nacos.config.file-extension=properties 配置使用的后缀名,一般只使用
properties和yaml两种格式
spring.cloud.nacos.config.prefix=nacos-service 配置DataId名称,默认就是服务名称。
可以人为指定在Nacos中创建的DataID值
spring.cloud.nacos.config.group=DEFAULT_GROUP 默认分组名称
spring.cloud.nacos.config.namespace=public所使用的名空间
# 设置配置中心服务端地址
spring.cloud.nacos.config.server-addr=localhost:8848
# Nacos 配置中心的namespace。需要注意,如果使用 public 的 namcespace ,请不要填写这
个值,直接留空即可
spring.cloud.nacos.config.namespace=public
# 配置自动刷新 对应的格式为nacos:服务名称.properties
spring.config.import=nacos:nacos-config-example.properties?refresh=true

3、核心配置文件application.properties

# Nacos帮助文档: https://nacos.io/zh-cn/docs/concepts.html
spring.application.name=nacos-service
# Nacos 服务发现与注册配置,其中子属性 server-addr 指定 Nacos 服务器主机和端口
spring.cloud.nacos.discovery.server-addr=localhost:8848
# 注册到 nacos 的指定 namespace,默认为 public
spring.cloud.nacos.discovery.namespace=public
# 应用服务 WEB 访问端口
server.port=8080

4、定义控制器类可以读取配置信息 yan.date.format

@RefreshScope
@RestController
public class HelloController {
	@Value("${yan.date.format}") //SpEL
	private String dateFormat;
	@GetMapping("/hello")
	public String hello(String name) {
	return new SimpleDateFormat(dateFormat).format(new Date()) +"said:'hello " + name + "!'";
	}
}

5、在Nacos的webUI中使用图形化界面工具的方式创建一组配置
在这里插入图片描述
一般规则【最佳软件开发实践】

  • 命名空间Namespace:不同的项目可以分为不同的命名空间。
  • 配置分组Group:根据项目的不同环境可以一个分组。
  • 配置集Data ID:服务不同环境的不同配置,就是一个配置集

在webUI中可以查看所有的配置信息,并允许编辑修改
在这里插入图片描述
查看历史配置版本
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值