02Nacos和Feign及Gateway配置

一、Nacos配置管理

1.统一配置管理

配置更改热更新

 ①在Nacos中添加配置信息:

 ②在弹出表单中填写配置信息:

 2.配置获取的步骤如下

 配置文件bootstrap.yml的优先级比application.yml优先级高。把nacos地址放入bootstrap.yml。

①在userservice中引入Nacos的配置管理客户端依赖:

<!--nacos配置管理依赖-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>

②在userservice中的resource目录添加一个bootstrap.yml文件,这个文件是引导文件,优先级高于application.yml:

spring:
  application:
    name: userservice # 服务名称
  profiles:
    active: dev # 环境
  cloud:
    nacos:
      server-addr: localhost:8848 # nacos地址
      config:
        file-extension: yaml # 文件后缀名

在微服务中添加bootstrap.yml,配置nacos地址、当前环境、服务名称、文件后缀名。这些决定了程序启动时去nacos读取哪个文件。

③在user-service中将pattern.dateformat这个属性注入到UserController中做测试

 ④访问http://localhost:8081/user/now获取时间对应格式,配置生效

 

3.配置自动更新

Nacos配置更新,无需重启微服务就可以配置更新。

方式一:在@Value注入的变量所在类上添加注解@RefreshScope

方式二:

使用@ConfigurationProperties注解

①创建一个配置类PatternProperties

@Component
@Data
@ConfigurationProperties(prefix = "pattern") // 跟配置文件的顶级名一致
public class PatternProperties {
   private String dateformat;
}

②在需要用的controller进行注入

 

总结:

  • 通过@Value注解注入,结合@RefreshScope来刷新
  • 通过@ConfigurationProperties注入,自动刷新

注意事项:

  • 不是所有的配置都适合放到配置中心,维护起来比较麻烦
  • 建议将一些关键参数,需要运行时调整的参数放到nacos配置中心,一般都是自定义配置

4.多服务共享配置

启动的时候从nacos读取多个配置文件优先级

userservice-dev.yaml>userservice.yaml>application.yml

无论profile如何变化,[spring.application.name].yaml这个文件一定会加载,因此多环境共享配置可以写入这个文件。

总结:

 

 二、http客户端Feign

1.RestTemplate方式存在的问题

RestTemplate远程调用的代码

String url = "http://userservice/user/" + order.getUserId();
User user = restTemplate.getForObject(url, User.class);

①代码可读性差,编程体验不统一

②参数复杂时URL难以维护

2.定义和使用Feign客户端

①在orderservice导入依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId> 
</dependency>

②在启动类添加注解开启Feign功能@EnableFeignClients

 ③编写Feign客户端接口

@FeignClient("userservice") //提供者名
public interface UserClient {
    @GetMapping("/user/{id}") 
    User findById(@PathVariable("id") Long id);
}

④使用Feign客户端代替RestTemplate

总结:

  • 引入依赖
  • 添加@EnableFeignClients注解
  • 编写FeignClient接口
  • 使用FeignClient中定义的方法代替RestTemplate

3.配置Feign日志的两种方式

feign.Logger.Level 修改日志级别 包含四种不同的级别:NONE、BASIC、HEADERS、FULL

方式一

配置文件方式

①全局生效

 ②局部生效

方式二

①声明一个Bean

public class FeignClientConfiguration {
    @Bean
    public Logger.Level feignLogLevel(){
        return Logger.Level.BASIC; 
    }
}

②全局配置,则把它放到@EnableFeignClients这个注解中

@EnableFeignClients(defaultConfiguration = FeignClientConfiguration.class)

③局部配置,则把它放到@FeignClient这个注解

@FeignClient(value="userservice",configuration = FeignClientConfiguration.class)

总结

方式一是配置文件,feign.client.config.xxx.loggerLevel

  • 如果xxx是default则代表全局
  • 如果xxx是服务名称,例如userservice则代表某服务

方式二是java代码配置Logger.Level这个Bean

  • 如果在@EnableFeignClients注解声明则代表全局
  • 如果在@FeignClient注解中声明则代表某服务

4.Feign性能优化

①Feign连接池的设置

引入httpClient依赖

 配置连接池

优化总结

  • 日志级别尽量用basic
  • 使用HttpClient或OKHttp代替URLConnection

        引入feign-httpClient依赖

        配置文件开启httpClient功能,设置连接池参数

5.Feign的最佳实践

方式一(继承):给消费者的FeignClient和提供者controller定义统一的父接口。然后实现接口

缺点

  • 服务紧耦合
  • 父接口参数列表中的映射不会被继承

方式二(抽取):将FeignClient抽取为独立模块,并且把接口有关的POJO、默认的Feign配置都放到这个模块中,提供给所有消费者使用

6.抽取FeignClient

  • 首先创建一个module,命名为feign-api,然后引入feign的starter依赖

  • 将order-service中编写的UserClient、User、DefaultFeignConfiguration都复制到feign-api项目中

  • 在order-service中引入feign-api的依赖

  • 修改order-service中的所有与上述三个组件有关的import部分,改成导入feign-api中的包
  • 重启测试

注意:

当定义的FeignClient不在SpringBootApplication的扫描包范围时,这些FeignClient无法使用。有两种方式解决:

方式一:指定FeignClient所在包

@EnableFeignClients(basePackages = "cn.itcast.feign.clients")

方式二:指定FeignClient字节码

@EnableFeignClients(clients = {UserClient.class})

三、统一网关Gateway

1.为什么需要网关

①对用户请求做身份验证、权限校验。

②将用户请求路由到微服务,实现负载均衡

③用户请求做限流

2.网关技术的实现

SpringCloud实现网关的方式

①gateway

②zuul

Zuul是基于Servlet的实现,属于阻塞式编程。而SpringCloudGateway则是基于Spring5中提供的WebFlux,属于响应式编程的实现,具备更好的性能。

3.搭建网关服务

①创建新的module,引入SpringCloudGateway的依赖和nacos的服务发现依赖:

<!--nacos客户端服务发现依赖-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--gateway-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

②编写路由配置及nacos地址

server:
  port: 10010
spring:
  application:
    name: gateway
  cloud:
    nacos:
      server-addr: localhost:8848 #nacos地址
    gateway:
      routes:
        - id: user-service #路由标识,唯一
          uri: lb://userservice # 路由的目标地址
          predicates: # 判断请求的规则
            - Path=/user/** # 路径的规则
        - id: order-service #路由标识,唯一
          uri: lb://orderservice # 路由的目标地址
          predicates: # 判断请求的规则
            - Path=/order/** # 路径的规则

③测试 http://localhost:10010/order/101

端口请求访问的是网关,基于路由规则判断,拉取服务列表,进行负载均衡发送请求。

总结:

4.路由断言工厂 Route Predicate Factory

  • 在配置文件中写的断言规则只是字符串,这些字符串会被Predicate Factory读取并处理,转变为路由判断的条件
  • Path=/user/**是按照路径匹配,这个规则是由org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory类来处理的

 

问题

  • PredicateFactory的作用是什么?

        读取用户定义的断言条件,对请求做出判断

  • Path=/user/**是什么含义?

        路径是以/user开头的就认为是符合的

5.过滤工厂GatewayFilterFactory

GatewayFilter是网关提供的一种过滤器,对进入网关的请求和微服务的返回的响应做处理

过滤工厂 

案例:所有进入userservice的请求添加一个请求头

请求头:Truth=itcast is freaking awesome!

①在gateway的配置文件application.yml添加过滤配置

 ②在user-service的UserController,获取请求头参数

@GetMapping("/prop")
public String prop(@RequestHeader(value = "Truth", required = false) String truth) {
    return truth;
}

③访问http://localhost:10010/user/prop

注意:

所有的路由都生效的过滤器

总结

  • 过滤器的作用是什么?

        对路由的请求或响应做加工处理,比如添加请求头

        配置在路由下的过滤器只对当前路由的请求生效

  • defaultFilters的作用是什么?

        对所有路由都生效的过滤器

6.全部过滤器

实现GlobalFilter接口

public interface GlobalFilter {
   Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain);
}

ServerWebExchange:请求上下文,获取request,response信息

GatewayFilterChain:把请求交给下一个过滤器

案例:定义全局过滤器,拦截并判断用户身份

判断请求的参数是否满足下面条件:

  • 参数中是否有authorization,
  • authorization参数值是否为admin

如果同时满足则放行,否则拦截

步骤:

①在gateway编写自定义全局过滤器

@Order(-1)
@Component
public class AuthorizeFilter implements GlobalFilter {
   @Override
   public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
      // 1.获取请求参数
      MultiValueMap<String, String> params = exchange.getRequest().getQueryParams();
      // 2.获取参数的authorization
      String auth = params.getFirst("authorization");
      // 3.判断是否是admin
      if ("admin".equals(auth)){
         // 放行
         return chain.filter(exchange);
      }

      //4.不放行就禁止
      exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
      // 5.结束处理
      return exchange.getResponse().setComplete();
   }
}

②发起请求

 总结

 

7.过滤器执行顺序

请求进入网关会碰到三类过滤器:DefaultFilter、当前路由的过滤器、GlobalFilter

①每一个过滤器都必须指定一个int类型的order值,order值越小,优先级越高,执行顺序越靠前。

②当order值一样时,顺序是defaultFilter最先,然后是局部的路由过滤器,最后是全局过滤器

8.跨域问题处理

在实际项目中,前后端分成两个不同的项目,各自部署在不同的域名下,这也就会遇到跨域问题了。浏览器禁止请求的发起者与服务端发生跨域ajax请求,请求被浏览器拦截的问题

解决方案:CORS

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值