此篇文章是在B站学习黑马SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式时所做的笔记。
- 1.Nacos配置管理
- 1.1 统一配置管理
- 1.1.1在Nacos中管理配置的步骤:
- 1.1.2 微服务怎么获取这些配置信息?
- 1.2 配置热更新
- 1.3 配置共享
- 1.3.1 共享环境添加
- 1.3.2 多种配置的优先级
- 1.4 搭建Nacos集群
- 2.Http客户端Feign
- 2.1 Feign代替RestTemplate
- 2.2 自定义配置
- 2.3 Feign使用优化
- 2.4 最佳实践
- 2.4.1 使用方式二抽取
- 3.统一网关Gateway
- 3.1 为什么需要网关
- 3.2 gateway快速入门
- 3.3 断言工厂
- 3.3.1 路由断言工厂Route Predicate Factory
- 3.4 过滤器工厂
- 3.4.1 GatewayFilter路由过滤器
- 3.5 全局过滤器
- 3.6 过滤器的执行顺序
- 3.7 跨域问题
- 3.7.1 解决跨域问题
1.1 统一配置管理Nacos不仅可以做注册中心,还可以配置管理服务。
当微服务的部署越来越多时,我们微服务配置就会越来越多,如果不想逐个管理起来,我们就可以通过Nacos的配置管理服务把它们集中起来管理。
1.1.1在Nacos中管理配置的步骤: 1.1.2 微服务怎么获取这些配置信息?微服务获取配置信息流程如下:
nacos中的配置文件会和application.yml配置文件合并,这时候nacos的地址就要在读取nacos配置文件之前被读取到,所有就要使用bootstrap.yml(优先级高于application.yml和nacos里的配置文件)这个配置文件。
配置步骤:
- 引入Nacos配置管理客户端依赖。
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-nacos-configartifactId>
dependency>
- 在服务消费者的resource目录添加一个bootstrap.yml文件,这个文件是引导文件。
# 需要去把在application里面的重复的配置删除
spring:
application:
name: userservice # 服务名称
profiles:
active: dev #开发环境,这里是dev
cloud:
nacos:
server-addr: localhost:8848 # Nacos地址
config:
file-extension: yaml # 文件后缀名
- 测试,用在Nacos管理配置中的pattern.dateformat属性注入到UserController中做测试:
@RestController
@RequestMapping("/user")
public class UserController {
// 注入nacos中的配置属性
@Value("${patten.dateformat}")
private String dateformat;
// 编写controller,通过日期格式化器来格式化现在时间并返回
@GetMapping("now")
public String now(){
return LocalDateTime.now().format(DateTimeFormatter.ofPattern(dateformat));
}
}
1.2 配置热更新
我们要实现修改Nacos配置后,微服务无需重启就可以让配置生效,这就是配置热更新。
方式一:在@Value注入的变量所在类上加上@RefreshScope
@RestController
@RequestMapping("/user")
@RefreshScope
public class UserController {
// 注入nacos中的配置属性
@Value("${patten.dateformat}")
private String dateformat;
}
方式二:使用@ConfigurationProperties
注解
@Data
@Component
@ConfigurationProperties(prefix = "patten")
public class PatternProperties {
private String dateformat;
}
@RestController
@RequestMapping("/user")
@RefreshScope
public class UserController {
@Autowired
private PatternProperties properties;
}
小结:Nacos配置更改后,要想使用热更新,有两种方式:① 通过@Value注入结合@RefreshScope一起使用;② 通过@ConfigurationProperties("prefix=“xx”)注入。
注意:
- 不是所有的配置都适合放到配置中心,不然维护起来会比较麻烦。
- 建议将一些关键参数,需要运行时调整的参数放到nacos配置中心,一般都是自定义的配置。
微服务启动时会读取nacos的多个配置文件,列如:
-
[spring.application.name]-[spring.profiles.active].yaml,例如:userservice-dev.yaml
-
[spring.application.name].yaml,例如:userservice.yaml
1.3.1 共享环境添加 1.3.2 多种配置的优先级[spring.application.name].yaml 没有环境,所有它是可以被多个环境共享的。
1.4 搭建Nacos集群[服务名]-[环境].yaml > [服务名称].yaml > 本地配置
略
2.Http客户端Feign我们先来看看利用RestTemplate
发起远程调用的代码和Feign
发起的远程调用代码对比一下。
//RestTemplate发起远程调用
String url = "http://userservice/user/" + order.getUserId();
User user = restTemplate.getForObject(url, User.class);
//Feign发起的远程调用
User user = userClient.findById(order.getUserId());
RestTemplate存在的缺点:① 代码可读性差,编程体验不统一;② 参数复杂URL难以维护。
2.1 Feign代替RestTemplateFeign的使用步骤:
- 引入依赖:
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-openfeignartifactId>
dependency>
- 在order-service的启动类添加
@EnableFeignClients
开启Feign功能
@EnableFeignClients // 添加这个注解开启Feign功能
@MapperScan("cn.itcast.order.mapper")
@SpringBootApplication
public class OrderApplication {
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class, args);
}
}
- 编写Feign客户端
@FeignClient("userservice") // 里面的值是被远程调用的服务名称
public interface UserClient {
@GetMapping("/user/{id}")
User findById(@PathVariable("id") Long id);
}
/*
主要是基于SpringMVC的注解来声明远程调用的信息:
服务名称:userservice
请求方式:GET
请求路径:/user/{id}
请求参数:Long id
返回值类型:User
*/
- 用Feign代替RestTemplate
2.2 自定义配置小结:Feign的使用步骤:① 引入依赖,② 添加@EnableFeignClients注解,③ 编写FeignClient接口,④ 使用FeignClient中定义的方法代替RestTemplate
Feign运行自定义配置来覆盖默认配置,可以修改的配置如下:
类型 | 作用 | 说明 |
---|---|---|
feign.Logger.Level | 修改日志级别 | 包含四种不同的级别:NONE、BASIC、HEADERS、FULL |
feign.codec.Decoder | 响应结果的解析器 | http远程调用的结果做解析,例如解析json字符串为java对象 |
feign.codec.Encoder | 请求参数编码 | 将请求参数编码,便于通过http请求发送 |
feign. Contract | 支持的注解格式 | 默认是SpringMVC的注解 |
feign. Retryer | 失败重试机制 | 请求失败的重试机制,默认是没有,不过会使用Ribbon的重试 |
配置Feign日志的两种方式:
方式一:配置文件方式
- 全局生效:
feign:
client:
config:
default: # 这里用default就是全局配置,如果是写服务名称,则是针对某个微服务的配置
loggerLevel: FULL # 日志级别
- 局部生效:
feign:
client:
config:
userservice: # 针对某个微服务的配置
loggerLevel: FULL # 日志级别
而日志的级别分为四种:
- NONE:不记录任何日志信息,这是默认值。
- BASIC:仅记录请求的方法,URL以及响应状态码和执行时间
- HEADERS:在BASIC的基础上,额外记录了请求和响应的头信息
- FULL:记录所有请求和响应的明细,包括头信息、请求体、元数据。
方式二:java代码方式,需要先声明一个@Bean
- 先创建一个类,在声明一个@bean。
public class DefaultFeignConfiguration {
@Bean
public Logger.Level feignLogLevel(){
return Logger.Level.BASIC; // 日志级别为BASIC
}
}
- 如果是全局配置,则把它放到@EnableFeignClients这个注解中。
@EnableFeignClients(defaultConfiguration = DefaultFeignConfiguration .class)
- 如果是局部配置,则把它放到@FeignClient这个注解中。
@FeignClient(value = "userservice", configuration = DefaultFeignConfiguration .class)
2.3 Feign使用优化
Feign底层的客户端实现:
-
URLConnection:默认实现,不支持连接池(所以影响性能)
-
Apache HttpClient :支持连接池
-
OKHttp:支持连接池
优化Feign的性能:
① 使用连接池代替默认的URLConnection;② 日志级别,最好用basic或none。
Feign的性能优化-连接池配置
- 在order-service的pom文件中引入Apache的HttpClient依赖。
<dependency>
<groupId>io.github.openfeigngroupId>
<artifactId>feign-httpclientartifactId>
dependency>
- 配置连接池,在order-service的application.yml中添加配置。
feign:
client:
config:
default: # default全局的配置
loggerLevel: BASIC # 日志级别,BASIC就是基本的请求和响应信息
httpclient:
enabled: true # 开启feign对HttpClient的支持
max-connections: 200 # 最大的连接数
max-connections-per-route: 50 # 每个路径的最大连接数
2.4 最佳实践
方式一(继承):给服务消费者的FeignClient和服务提供者的XxxController继承同一个接口。
方式二(抽取):将FeignClient、POJO、Feign的默认配置都封装到一个模块当中,提供给服务消费者使用。
2.4.1 使用方式二抽取- 创建一个模块用来保存要抽取的类和引入Feign远程调用依赖
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-openfeignartifactId>
dependency>
-
在要发起远程调用的模块引入feign-api依赖,在把抽取出去的类删除。
-
解决扫描包问题。
方式一:指定feign应该扫描的包
@EnableFeignClients(basePackages = "cn.itcast.feign.client")
方式二:指定需要加载的Client接口
@EnableFeignClients(clients = {UserClient.class})
3.统一网关Gateway
3.1 为什么需要网关
我们的业务不全是对外公开的,有些业务只能是公司的工作人员去访问,这时候就需要网关来统一入口。
网关功能:① 对用户请求做身份认证、权限校验;② 将用户请求路由到微服务,并实现负载均衡;③ 对用户请求做限流。
通俗的来说网关就是用来保护微服务的。
在SpringCloud中网关的实现有两种:① gateway;② zuul。
gateway是基于Spring5中提供的WebFlux,属于响应式编程的实现,具备更好的性能;Zuul是基于Servlet的实现,属于阻塞式编程。
3.2 gateway快速入门实现网关基本路由功能的步骤:
- 创建SpringBoot模块,引入nacos客户端依赖和网关依赖。
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-gatewayartifactId>
dependency>
-
编写启动类
-
编写基础配置和路由功能
server:
port: 10010 # 网关端口
spring:
application:
name: gateway # 服务名称
cloud:
nacos:
server-addr: localhost:8848 # nacos地址
gateway:
routes: # 网关路由配置
- id: user-service # 路由id,自定义,只要唯一即可
# uri:http://127.0.0.1:8081 # 路由的目标地址http就是固定地址
uri: lb://userservice #路由的目标地址lb就是负载均衡,后面跟服务名称
predicates: # 路由断言,也就是判断请求是否符合路由规则的条件
- Path=/user/** # 这个是按照路径匹配,只要以/user/开头就符合要求
- id: order-service
uri: lb://orderservice
predicates:
- Path=/order/**
- 重启测试
重启网关,访问http://localhost:10010/user/1时,符合/user/**
规则,请求会转发到uri:http://userservice/user/1。
- 网关路由流程图
我们在配置文件中写的断言规则只是字符串,这些字符串会被Predicate Factory读取并处理,转变为路由判断的条件
例如Path=/user/**是按照路径匹配,这个规则是由
org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory
类来
Spring提供了11种基本的Predicate工厂:
名称 | 说明 | 示例 |
---|---|---|
After | 是某个时间点后的请求 | - After=2037-01-20T17:42:47.789-07:00[America/Denver] |
Before | 是某个时间点之前的请求 | - Before=2031-04-13T15:14:47.433+08:00[Asia/Shanghai] |
Between | 是某两个时间点之前的请求 | - Between=2037-01-20T17:42:47.789-07:00[America/Denver], 2037-01-21T17:42:47.789-07:00[America/Denver] |
Cookie | 请求必须包含某些cookie | - Cookie=chocolate, ch.p |
Header | 请求必须包含某些header | - Header=X-Request-Id, \d+ |
Host | 请求必须是访问某个host(域名) | - Host=.somehost.org,.anotherhost.org |
Method | 请求方式必须是指定方式 | - Method=GET,POST |
Path | 请求路径必须符合指定规则 | - Path=/red/{segment},/blue/** |
Query | 请求参数必须包含指定参数 | - Query=name, Jack或者- Query=name |
RemoteAddr | 请求者的ip必须是指定范围 | - RemoteAddr=192.168.1.1/24 |
Weight | 权重处理 |
我们可以在SpringCloud官网查询这11个断言工厂的用法,官网:https://spring.io/projects/spring-cloud。
下面是断言工厂After用法。
server:
port: 10010 # 网关端口
spring:
application:
name: gateway # 服务名称
cloud:
nacos:
server-addr: localhost:8848 # nacos地址
gateway:
routes: # 网关路由配置
- id: user-service # 路由id,自定义,只要唯一即可
# uri:http://127.0.0.1:8081 # 路由的目标地址http就是固定地址
uri: lb://userservice #路由的目标地址lb就是负载均衡,后面跟服务名称
predicates: # 路由断言,也就是判断请求是否符合路由规则的条件
- Path=/user/** # 这个是按照路径匹配,只要以/user/开头就符合要求
- After=2037-01-20T17:42:47.789-07:00[America/Denver] # 断言工厂After用法
- id: order-service
uri: lb://orderservice
predicates:
- Path=/order/**
3.4 过滤器工厂
3.4.1 GatewayFilter路由过滤器
GatewayFilter是网关中提供的一种过滤器,可以对进入网关的请求和微服务返回的响应做处理:
Spring提供了31种不同的路由过滤器工厂,例如:
名称 | 说明 |
---|---|
AddRequestHeader | 给当前请求添加一个请求头 |
RemoveRequestHeader | 移除请求中的一个请求头 |
AddResponseHeader | 给响应结果中添加一个响应头 |
RemoveResponseHeader | 从响应结果中移除有一个响应头 |
RequestRateLimiter | 限制请求的流量 |
… |
案例:给所有进入userservice的请求添加一个请求头。
实现方式:在gateway中修改application.yml文件,给userservice的路由添加过滤器。
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://userservice
predicates:
- Path=/user/**
filters: # 过滤器
- AddRequestHeader=Truth, Itcast is freaking awesome! # 添加请求头
默认过滤器:如果要对所有的路由都生效,则可以将过滤器工厂写到default下。格式如下:
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://userservice
predicates:
- Path=/user/**
default-filters: # 默认过滤项
- AddRequestHeader=Truth, Itcast is freaking awesome!
3.5 全局过滤器
全局过滤器的作用也是处理一切进入网关的请求和微服务响应,与GatewayFilter效果一样;区别在于GatewayFilter是通过application.yml配置的,处理逻辑也是固定的;而GlobalFilter的逻辑需要自己写代码实现。
实现方式是实现GlobalFilter接口。
public interface GlobalFilter {
/**
* 处理当前请求,有必要的话通过{@link GatewayFilterChain}将请求交给下一个过滤器处理
*
* @param exchange 请求上下文,里面可以获取Request、Response等信息
* @param chain 用来把请求委托给下一个过滤器
* @return {@code Mono} 返回标示当前过滤器业务结束
*/
Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain);
}
自定义过滤器步骤:
- 实现GlobalFilter接口。
- 在实现GlobalFilter接口的类上面需要添加两个注解:
@Component
、@Order
(这个注解是执行这个过滤器的顺序值越小优先级越高,因为以后可能会定义很多个过滤器)。
请求进入网关会碰到三类过滤器:当前路由的过滤器、DefaultFilter、GlobalFilter。
请求路由后,会将当前路由过滤器和DefaultFilter、GlobalFilter,合并到一个过滤器链(集合)中,排序后依次执行每个过滤器。
路由过滤器、defaultFilter、全局过滤器的执行顺序:
-
order值越小,优先级越高
-
当order值一样时,顺序是defaultFilter最先,然后是局部的路由过滤器,最后是全局过滤器
跨域:域名不相同;域名相同,端口号不相同。
跨域问题:浏览器禁止请求的发起者与服务端发生跨域ajax请求,请求被浏览器拦截的问题。
3.7.1 解决跨域问题在gateway服务的application.yml文件中配置下的内容:
spring:
cloud:
gateway:
# 。。。
globalcors: # 全局的跨域处理
add-to-simple-url-handler-mapping: true # 解决options请求被拦截问题
corsConfigurations:
'[/**]':
allowedOrigins: # 允许哪些网站的跨域请求
- "http://localhost:8090"
allowedMethods: # 允许的跨域ajax的请求方式
- "GET"
- "POST"
- "DELETE"
- "PUT"
- "OPTIONS"
allowedHeaders: "*" # 允许在请求中携带的头信息
allowCredentials: true # 是否允许携带cookie
maxAge: 360000 # 这次跨域检测的有效期
SpringCloud复习01
SpringCloud复习03
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)