JavaWeb_SpringCloud微服务_Day2-Nacos, Feign, GateWay

JavaWeb_SpringCloud微服务_Day2-Nacos, Feign, GateWay

  • nacos
    • 统一配置管理
    • 配置热更新
    • 多环境配置共享
  • feign
    • 快速入门
    • 自定义配置
    • 性能优化
    • 最佳实践
  • GateWay
    • 介绍
    • 快速入门
    • 路由断言工厂
    • 过滤器
    • 全局过滤器
    • 过滤器执行顺序
    • 跨域
  • 来源

nacos

统一配置管理

  • 依赖
    
    <dependency>
        <groupId>com.alibaba.cloudgroupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-configartifactId>
    dependency>
    
  • bootstrap.yml
    spring:
        application:
            name: userservice # 服务名称
        profiles:
            active: dev # 开发环境
        cloud:
            nacos:
            server-addr: localhost:8848 # Nacos地址
        #      discovery:
        #        # cluster-name: SH
        #        namespace: 84c5c3c0-8065-468b-8708-5f699f392f67 # 命名空间
            config:
                namespace: 84c5c3c0-8065-468b-8708-5f699f392f67 # 命名空间
                file-extension: yaml # 文件后缀名
    
  • 拉取配置
    @Value("${pattern.dateformat}")
    private String dateformat;
    
    @GetMapping("/now")
    public String now()
    {
        return LocalDateTime.now().format(DateTimeFormatter.ofPattern(dateformat));
    }
    
  • 总结
    • nacos配置读取在本地配置读取之前, 所以需要引入bootstrap.yml写入nacos配置, bootstrap.yml的优先级很高
    • 服务名称+开发环境+文件后缀名 = 读取文件id

配置热更新

  • 通过@Value注解注入, 结合@RefreshScope来刷新
    @RefreshScope
    public class UserController {
    
        @Value("${pattern.dateformat}")
        private String dateformat;
    }
    
  • 通过@ConfigurationProperties注入, 自动刷新
    @Component
    @ConfigurationProperties(prefix = "pattern")
    public class PatternProperties {
        private String dateformat;
    }
    
  • 注意事项
    • 不是所有的配置都式和放到配置中心, 维护起来比较麻烦
    • 建议将一些关键参数, 需要运行时调整的参数放到nacos配置中心, 一般都是自定义配置

多环境配置共享

微服务会从nacos读取的配置文件

  • [服务名]-[spring.profile.active].yaml, 环境配置
  • [服务名].yaml, 默认配置, 多环境共享

优先级
[服务名]-[环境].yaml > [服务名].yaml > 本地配置

feign

快速入门

  1. 引入依赖
    <dependency>
        <groupId>org.springframework.cloudgroupId>
        <artifactId>spring-cloud-starter-openfeignartifactId>
    dependency>
    
  2. 启动类添加注解开启Feign
    @EnableFeignClients
    public class OrderApplication {
        public static void main(String[] args) {
            SpringApplication.run(OrderApplication.class, args);
        }
    }
    
  3. 编写Feign客户端
    @FeignClient("userservice")
    public interface UserClient {
        @GetMapping("/user/{id}")
        User findById(@PathVariable Long id);
    }
    
  4. 用Feign客户端代替RestTemplate
    @Autowired
    private UserClient userClient;
    
    public Order queryOrderById(Long orderId) {
        // 1.查询订单
        Order order = orderMapper.findById(orderId);
        // 2. 利用Feign发起http请求, 查询用户
        User user = userClient.findById(order.getUserId());
        // 3 封装user到order
        order.setUser(user);
        // 4.返回
        return order;
    }
    

自定义配置

类型 作用 说明
feign.Logger.Level 修改日志级别 包含四种不同的级别:NONE、BASIC、HEADERS、FULL
feign.codec.Decoder 响应结果的解析器 http远程调用的结果做解析,例如解析json字符串为java对象
feign.codec.Encoder 请求参数编码 将请求参数编码,便于通过http请求发送
feign.Contract 支持的注解格式 默认是SpringMVC的注解
feign.Retryer 失败重试机制 请求失败的重试机制,默认是没有,不过会使用Ribbon的重试
  • 通过配置文件
    feign:
    client:
        config:
        default: # default是全局配置
            loggerLevel: FULL # 日志级别
    #      userservice: # 单个微服务的配置
    #        loggerLevel: FULL # 日志级别 
    
  • 通过代码
// 声明Bean
public class DefaultFeignConfiguration {
    @Bean
    public Logger.Level feignLogLevel()
    {
        return Logger.Level.BASIC;
    }
}

// 在启动类添加注解
// 全局配置
@EnableFeignClients(defaultConfiguration = DefaultFeignConfiguration.class)
// 局部配置
@FeignClient(value = "userservice", configuration = DefaultFeignConfiguration.class)

性能优化

Feign底层的客户端实现

  • URLConnection: 默认实现, 不支持连接池
  • Apache HttpClient: 支持连接池
  • OKHttp: 支持连接池

优化Feign性能主要包括

  • 使用连接池代替默认的URLConnection
  • 日志级别, 最好用basic或none

连接池配置

  • 依赖
    <dependency>
        <groupId>io.github.openfeigngroupId>
        <artifactId>feign-httpclientartifactId>
    dependency>
    
  • 配置
    feign:
    httpclient:
        enabled: true # 开启feign对HttpClient的支持
        max-connections: 200 # 最大的连接数
        max-connections-per-route: 50 # 每个路径的最大连接数
    

最佳实践

  • 方式一(继承): 给消费者的FeignClient和提供者的controller定义统一的父接口作为标准
    • 服务紧耦合
    • 父接口参数列表中的映射不会被继承
  • 方式二(抽取): 将FeignClient抽取为独立模块, 并且把接口有关的pojo, 默认的feign配置都放到这个模块中, 提供给消费者使用
    1. 首先创建一个module,命名为feign-api,然后引入feign的starter依赖
      <dependencies>
          <dependency>
              <groupId>org.springframework.cloudgroupId>
              <artifactId>spring-cloud-starter-openfeignartifactId>
          dependency>
      dependencies>
      
    2. 将order-service中编UserClient、User、DefaultFeignConfiguration都复制到feign-api项目中
    3. 在order-service中引入feign-api的依赖
      <dependency>
          <groupId>cn.itcast.demogroupId>
          <artifactId>feign-apiartifactId>
          <version>1.0version>
      dependency>
      
    4. 修改order-service中的所有与上述三个组件有关的import部分,改成导入feign-api中的包
    5. 导入FeignClient(启动类)
      // 方式一: 指定FeignClient所在包
      @EnableFeignClients(basePackages = "cn.itcast.feign.clients")
      // 方式二: 指定FeignClient字节码
      @EnableFeignClients(clients = {UserClient.class})
      

GateWay

介绍

网关的作用

  • 对用户请求做身份认证, 权限校验
  • 将用户请求路由到微服务, 并实现负载均衡
  • 对用户请求做限流

SpringCloud中网关的实现

  • GateWay
  • Zuul

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

快速入门

  1. 创建module, 引入SpringCloudGateWay依赖和nacos服务发现依赖
    <dependency>
        <groupId>org.springframework.cloudgroupId>
        <artifactId>spring-cloud-starter-gatewayartifactId>
    dependency>
    <dependency>
        <groupId>com.alibaba.cloudgroupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
    dependency>
    
  2. application.yml
    server:
    port: 10010
    spring:
    application:
        name: gateway
    cloud:
        nacos:
        server-addr: localhost:8848
        gateway:
        routes: # 网关路由配置
            - id: user-service # 路由id, 自定义, 唯一即可
            # uri: http://127.0.0.1:8081 # 固定地址
            uri: lb://userservice # lb就是负载均衡, 后面跟服务名称
            predicates: # 路由断言, 也就是判断请求是否符合路由规则的条件
                - Path=/user/** # 这个是按照路径匹配, 只要以/user/开头就符合要求
            - id: order-service
            uri: lb://orderserver
            predicates:
                - Path=/order/**
    
    

路由断言工厂

Spring提供了11种Predi工厂

名称 说明
After 是某个时间点后的请求
Before 是某个时间点之前的请求
Between 是某两个时间点之前的请求
Cookie 请求必须包含某些cookie
Header 请求必须包含某些header
Host 请求必须是访问某个host (域名)
Method 请求方式必须是指定方式
Path 请求路径必须符合指定规则
Query 请求参数必须包含指定参数
RemoteAddr 请求者的ip必须是指定范围
Weight 权重处理

过滤器

  • 配置
    spring:
        cloud:
            gateway:
                routes: # 网关路由配置
                    filters: # 过滤器
                        - AddRequestHeader=Truth, Itcast is freaking awesome! # 添加请求头
    
  • 代码
    public User queryById(@PathVariable("id") Long id,
                        @RequestHeader(value = "Truth", required = false) String truth) {
        System.out.println("truth: "+truth);
        return userService.queryById(id);
    }
    
  • 对所有路由生效的配置
      spring:
          cloud:
              gateway:
                  default-filters: # 默认过滤器, 会对所有的路由器请求都生效
                    - AddRequestHeader=Truth, Itcast is freaking awesome! # 添加请求头 
    

全局过滤器

@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. 校验
        if("admin".equals(auth)){
            // 放行
            return chain.filter(exchange);
        }
        // 4. 拦截
        // 4.1 禁止访问
        exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
        // 4.2 结束处理
        return exchange.getResponse().setComplete();
    }
}

过滤器执行顺序

  • order值越小, 优先级越高
  • order值一样时, defaultFilter>局部的路由过滤器>全局过滤器

跨域

跨域:域名不一致就是跨域,主要包括

  • 域名不同: www.taobao.com 和 www.taobao.org 和 www.jd.com 和miaosha,jd.com
  • 域名相同,端口不同: localhost:8080和localhost:8081
  • 跨域问题: 浏览器禁止请求的发起者与服务端发生跨域ajax请求,请求被浏览器拦截的问题
  • 解决方案: CORS

配置

spring:
  cloud:
    gateway:
      globalcors: # 全局的跨域处理
        add-to-simple-url-handler-mapping: true # 解决options请求被拦截问题
        corsConfigurations:
          '[/**]':
            allowedOrigins: # 允许哪些网站的跨域请求
              - "http://localhost:8090"
              - "http://www.leyou.com"
            allowedMethods: # 允许的跨域ajax的请求方式
              - "GET"
              - "POST"
              - "DELETE"
              - "PUT"
              - "OPTIONS"
            allowedHeaders: "*" # 允许在请求中携带的头信息
            allowCredentials: true # 是否允许携带cookie
            maxAge: 360000 # 这次跨域检测的有效期

来源

黑马程序员. SpringCloud微服务

你可能感兴趣的:(JavaWeb开发,#,nacos,gateway,feign,微服务,spring,cloud,spring,boot,java)