当前位置: 首页 > article >正文

SpringCloud基础学习

SpringCloud

private RestTemplate restTemplate;//提供多种边界访问远程http服务的方法,简单的Restful服务模板
//(url,实体:Map,Class<T> responseType)
​
@Autowired
private RestTemplate restemplate;
​
private static final String REST_URL_PREFIX = "http://localhost:8081";
​
@RequestMapping("/consumer/dept/add")
public boolean add(Dept dept){
    return restTemplate.postForObject(REST_URL_PREFIX+"/dept/add",dept,Boolean.class);
}

1.Ribbon

Ribbon负载均衡

负载均衡策略,通过定义IRule可以修改负载均衡规则,有两种方式

  1. 代码方式:在order-service中的OrderApplication类中,定义一个新的IRule:

    @Bean
    public IRule randomRule(){
        return new RandomRule();
    }
    //针对全局
  2. 配置文件方式:在order-service的application.yml文件中,添加新的配置也能修改规则

    userservice:
      ribbon:
        NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
    //针对某个微服务

Ribbon饥饿加载

Ribbon默认是采用懒加载,即第一次访问时才会去创建LoadBalanceClient,请求时间会很长。而饥饿加载则会在项目启动时创建,降低第一次访问的耗时,通过下面配置开启

ribbon:
  eager-load:
    enabled: true # 开启饥饿加载
    clients: userservice # 指定对userservice这个服务饿加载

2.Nacos

注册中心

服务注册

  1. 启动微服务

  2. 引入服务发现依赖

  3. 配置Nacos地址

  4. 查看注册中心效果

  5. 集群模式启动测试

服务集群属性

spring:
  cloud:
    nacos:
      server-addr: localhost:8848 # nacos服务端地址
      discovery: 
        cluster-name: HZ # 配置集群名称,也就是机房位置

服务发现

  1. 开启服务发现功能 @EnableDiscoveryClient

  2. 测试服务发现AI

@SpringBootTest
public class DiscoveryTest {
​
    @Autowired
    DiscoveryClient discoveryClient;
​
    @Test
    void discoveryClientTest(){
        for (String service : discoveryClient.getServices()){
            System.out.println("service = " + service);
            //获取ip+端口
            List<ServiceInstance> instances = discoveryClient.getInstances(service);
            for (ServiceInstance instance : instances) {
                System.out.println("ip:"+instance.getHost()+";"+"port = "+ instance.getPort());
            }
        }
    }
}

负载均衡

  1. 引入负载均衡依赖 spring-cloud-starter-localbalancer

  2. 测试负载均衡API LoadBalancerClient

  3. 测试远程调用 RestTemplate

  4. 测试负载均衡调用 @LoadBalanced

// 完成负载均衡的发送请求
private Product getProductFromRemoteWithLoadBalance(Long productId){
    //1.获取到商品服务所在的所有机型IP+port
    ServiceInstance choose = loadBalancerClient.choose("service-product");
    //远程URL
    String url = "http://"+choose.getHost()+":"+choose.getPort()+"/product/"+productId;
    log.info("远程请求:{}",url);
    //2.给远程发送请求
    Product product = restTemplate.getForObject(url,Product.class);
    return product;
}

也可以将@LoadBalanced写到远程调用客户端上,也可以实现负载均衡

// 基于注解负载均衡的发送请求
private Product getProductFromRemoteWithLoadBalance(Long productId){
    String url = "http://service-product/product/"+productId;
    //2.给远程发送请求 service-product会被动态替换
    Product product = restTemplate.getForObject(url,Product.class);
    return product;
}

如果注册中心宕机,远程调用还能成功嘛 两种情况,是否调用过

服务实例的权重设置

  1. 在Nacos控制台可以设置实例的权重值,首先选中实例后面的编辑按钮

  2. 将权重设置为0.1,测试可以发现8081被访问到的频率大大降低

环境隔离

Nacos中服务存储 和数据存储的最外层都是一个名为namespace的东西,用来做最外层隔离

修改order-service的application.yml,添加namespace:

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/zkw?useSSL=false
    namespace: root
    password: 123456
    driver-class-name: com.mysql.jdbc.Driver
  cloud:
    nacos:
      server-addr: localhost:8848
      discovery:
        cluster-name: SH # 上海
        namespace: # 命名空间
配置中心

设置 配置文件的id:[服务名称]-[profile].[后缀名]

基本使用

  1. 启动Nacos

  2. 引入依赖

    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
    </dependency>
  3. 在userservice中的resource目录添加一个bootstrap.yml文件,这个文件是引导文件

    spring:
      application:
        name: userservice # 服务名称
      profiles:
        active: dev # 开发环境
      cloud:
        nacos:
          server-addr: localhost:8848 # Nacos地址
          config:
            file-extension: yaml # 文件后缀名
  4. 创建data-id(数据集)

动态刷新

  1. @Value("${xx}")获取配置 + @RefreshScope 实现自动刷新

  2. @ConfigurationProperties 无感自动刷新

  3. NacosConfigManager 监听配置变化

Nacos中的数据集和application.properties有相同的配置,哪个会生效?

先导入优先,外部优先

nacos集群搭建

3.Feign

Feign是一个声明式的http客户端

定义和使用Feign客户端

  1. 引入依赖

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-openfeign</artifactId>
    <dependency>
  2. 在order-service的启动类添加注解并开启Feign的功能

    @EnableFeiClients
    @MapperScan("cn.itcast.order.mapper")
    @SpringBootApplication
    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("id") Long id);
    }

    主要是基于SpringMVC的注解来声明远程调用信息

Feign自定义配置

配置Feign日志有两种方式:

方式一:配置文件方式

  1. 全局生效:

    feign:
      client:
        config:
          default: #这里用default就是全局配置,如果是写服务器名称,则是针对某个微服务的配置
            loggerLevel: FULL #日志级别
  2. 局部生效

    feign:
      client:
        config:
          userservice:
            loggerLevel: FULL

方式二:java代码方式,需要先声明一个Bean

public class FeignClientConfiguration{
  @Bean
  public Logger.Level feignLogLevel(){
    return Logger.level.BASIC;
  }
}
  1. 全局配置:则把它放到@EnableFeignClients这个注解中

    @EnableFeignClients(defaultConfiguration = FeignClientConfiguration.class)
  2. 局部配置:则把它反到@FeignClient这个注解中

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

Feign性能优化

Feign底层实现:

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

  • Apache HttpClien:支持连接池

  • OKHttp:支持连接池

因此性能优化主要包括:

  1. 使用连接池代替默认的URLConnection

  2. 日志级别,最好用basic或none

性能优化-连接池配置

1.引入依赖

<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-httpclient</artifactId>
</dependency>

2.配置连接池

feign:
  client:
    config:
      default:
        loggerLevel: BASIC
  httpclient:
    enable: true
    max-connections: 200 #最大连接数
    max-connections-per-route:50 #mei'ge

Feign的最佳实践

方式一(继承):给消费者的FeignClient和提供者的controller定义统一的父接口作为标准

public interface UserAPI{
  @GetMapping("/user/{id}")
  User findById(@PathVariable("id") Long id);
}
​
----------------------------------------------
    
@FeignClient(value = "userservice")
public interface UserClient extend UserAPI{
}
​
----------------------------------------------
    
@RestController
public class UserController implements UserAPI{
}

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

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

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

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

  4. 修改order-service中的所有与上述三个组件有关的import部分,改成导入feign-api中的包

  5. 重启测试

4.网关

网关功能:

  • 身份认证和权限校验

  • 服务路由、负载均衡

  • 请求限流

搭建网关服务

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

    <!--网关依赖-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-gateway</artifactId>
    </dependency>
    <!--nacos服务发现依赖-->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </dependency>
  2. 编写路由配置及nacos地址

    server:
      port: 10010 # 网管端口
    spring:
      application:
        name: getway # 服务名称
      cloud:
        nacos:
          server-addr: localhost:8848 # nacos地址
        gateway:
          routes: # 网关路由配置
            - id: user-service # 路由id,自定义,只要唯一即可
              # uri: 路由的目标地址 http就是固定地址
              uri: lb://userservice # 路由的目标地址 lb就是负载均衡,后面跟服务名称
              predicates: # 路由断言,也就是判断请求是否符合路由规则的条件
                - Path=/user/** # 这个是按照路径匹配,只要以/user/开头就符合要求

路由断言工厂

网关路由可以配置的内容包括:

  • 路由id:路由唯一标识

  • uri:路由目的地,支持lb和http两种

  • predicates:路由断言,盘软请求是否符合要求,符合则转发到路由目的地

  • filters:路由过滤器,处理请求或响应

路由的过滤器配置

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

给所有进入userservice的请求添加一个请求头

实现方式:在gateway中修改application.yml文件,给userservice的路由添加过滤器

spring:
  cloud:
    gateway:
      routes: #网关路由配置
        - id: userservice
          uri: lb://userservice
          predicates:
            - Path=/user/**
          filters: #过滤器
            - AddRequestHeader=Truth,Itcast is freaking awesome! #添加请求头

要对所有的路由都生效,则可以将过滤器工厂写道default下

spring:
  application:
    name: gateway #服务名称
  cloud:
    nacos:
      server-addr: localhost:8848 #nacos地址
    gateway:
      routes: #网关路由配置
        - id: userservice
          uri: lb://userservice
          predicates:
            - Path=/user/**
        - id: order-service
          uri: lb://orderservice
          predicates:
            - Path=/order/**
      default-filters: #默认过滤器,会对所有的路由请求都生效
            - AddRequestHeader=Truth,Itcast is freaking awesome! 

全局过滤器 GlobalFilter

全局过滤器的作用也是处理一切进入网关的请求和微服务响应,与GatewayFilter的作用一样定定义方式是实现GlobalFilter接口

@Order(-1)
@Component
public interface GlobalFilter {
    /**
     * 处理当前请求,有必要的话通过{@link GatewayFilterChain}将请求交给下一个过滤器
     *
     *@param exchange 请求上下文,里面可以获取Request、Response信息
     *@param chain 用来把请求委托给下一个过滤器
     *@return {@code Mono<void>} 返回标示当前过滤器业务结束
     */
    @Override
    Mono<Void> filter(ServerWebExchange exchange,GatewayFilterChain chain){
        //1.获取请求参数
        ServerHttpRequest request = exchange.getRequest();
        MultiValueMap<String,String> params = request.getQueryParams();
        //2.获取请求参数中的 authorization 参数
        String auth = params.getFirst("authorization");
        //3.判断参数值是否等于admin
        if("admin".equals(auth)){
            //4.是,放行
            return chain.filter(exchange);
        }
        //5.否,拦截
        //5.1 设置状态码
        exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
        //5.2 拦截请求
        return exchange.getResponse().setComplete();
    }
}

过滤器链执行顺序

每个过滤器都必须指定一个int类型的order值,order值越小,优先级越高,执行顺序越靠前;其中GlobalFilter由我们指定,路由过滤器和defaultFilter的order则是由Spring指定,默认是按照声明顺序从1开始

当过滤器的order值一样时 defaultFilter > 路由过滤器 > GlobalFilter

跨域问题处理

网关处理跨域采用的是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: 36000 #这次跨域检测的有效期

http://www.kler.cn/a/568848.html

相关文章:

  • 单片机知多少-STM32-GPIO-寄存器
  • 蓝桥杯刷题(Cows in a Skyscraper G,炮兵阵营)
  • java23种设计模式-迭代器模式
  • 数据挖掘实习面经一
  • CSS 系列之:选择器
  • Python接口自动化中操作Excel文件的技术方法
  • 【漫话机器学习系列】110.线性可分(Linearly Separable)
  • Android Audio基础(55)——音频常见指标
  • 【网络安全 | 渗透工具】自动化SSRF工具autossrf
  • 牛客周赛83:A:JAVA
  • JavaWeb个人笔记
  • 2024年中国城市统计年鉴(PDF+excel)
  • 大白话跨域问题怎么破,解决方法有啥?
  • 行为型模式 - 迭代器模式 (Iterator Pattern)
  • 蓝桥备赛(六)- C/C++输入输出
  • 设计模式Python版 观察者模式
  • 深度学习-14.深度强化学习:近端策略优化
  • vscode远程连接ubuntu/Linux(虚拟机同样适用)
  • 博客系统--测试报告
  • QT-对象树