springcloud

1.基础
2.服务与服务之间的远程调用
3.服务者-消费者
4.Eureka注册中心
5.Ribbon负载均衡
6.Nocos注册中心
7.Nocos配置管理
8.Feign实现远程调用http请求的发生
9.网关

基础

单体项目:将业务的所有的功能集中在一个项目中开发,打包成一个包部署
分布式架构:根据业务功能对系统进行拆分,每一个业务模块作为独立项目开发,成为一个服务
微服务:
1.每一个服务对应唯一的业务功能
2.每个服务相互独立,当a要访问b的接口时,b要暴漏业务接口
3.每个微服务数据都是独立的,部署独立
4.服务做好隔离性(调用其他服务时,出现问题)容错、降级,避免出现联机错误

服务与服务之间的远程调用

1.配置类注入bena RestTemplate
RestTemplate是Spring提供的用于访问Rest服务的客户端(调用其他请求)

package cn.itcast.order;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@MapperScan("cn.itcast.order.mapper")
@SpringBootApplication
public class OrderApplication {

    public static void main(String[] args) {
        SpringApplication.run(OrderApplication.class, args);
    }

    /**
     * 创建RestTemplate并注入spring容器   /  发送http请求
     * @return
     */
    @Bean
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
}

2.自动注入 RestTemplate 对象,调用方法进行微服务之间的远程调用

@RestController
@RequestMapping("order")
public class OrderController {

   @Autowired
   private OrderService orderService;

   @Autowired
   private RestTemplate restTemplate;

    @GetMapping("{orderId}")
    public Order queryOrderByUserId(@PathVariable("orderId") Long orderId) {
        // 1.根据id查询订单
        Order order = orderService.queryOrderById(orderId);
        // 2.调用RestTemplate发送http请求,查询用户
        // 2-1:查询用户请求
        String url = "http://localhost:8081/user/"+order.getUserId();
        // 2-2:传入请求,实现远程调用    getForObject:GET请求   postForObject: 发送post请求
        // 2-3:(url,user.class) restTemplate请求响应的json数据转化为实体对象
        User forObject = restTemplate.getForObject(url, User.class);
        order.setUser(forObject);
        return order;
    }

}

在这里插入图片描述

服务者-消费者

服务者:服务者暴漏端口给微服务调用
消费者:调用其他微服务提供的接口
一个服务既可以作为服务组,也可以作为消费者

Eureka注册中心

消费者如何获取提供者的具体信息

  • 服务者启动时向Eureka注册自己的信息
  • eureka保存这些信息
  • 消费者根据服务名称向Eureka拉取提供者信息

多个服务者,消费者如何选中

  • 消费者使用负载均衡算法,从列表挑选一个

消费者如何感知服务者将抗状态

  • 服务者每隔30秒向EuekaServer发送心跳请求,报告健康状况
  • Eureka会更新记录到服务列表信息,心跳不正常会被剔除
  • 消费者就可以拉取到最新的信息

Eureka服务端

  • 记录服务信息
  • 心跳监控

Eureka客户端

  • 服务提供者
    • 注册自己的信息到EurekaServer
    • 每隔30秒向EurekaServer发送心跳
  • 服务消费者
    • 根据服务者提供的服务名称向EurekaServer拉取服务列表
    • 基于列表做负载均衡算法,挑选服务进行远程调用

搭建

1.pom文件导入jar包

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
    </dependencies>

2.Eureka的启动类

@EnableEurekaServer  // 加入Eureka自动装配的开关
@SpringBootApplication
public class EurekaApplication {

    public static void main(String[] args) {
        SpringApplication.run(EurekaApplication.class, args);
    }

}

3.eureka的配置文件 eureka将自己也注册到注册中心

server:
  port: 10086  #服务端口
spring:
  application:
    name: eureka-server   # eureka的服务名称
eureka:
  client:
    service-url:     #eureka地址信息
      defaultZone: http://127.0.0.1:10086/eureka

4.访问http://127.0.0.1:10086/就可以访问到
在这里插入图片描述

服务注册到Eureka中

1.jar包

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

2.application.yaml配置服务

spring:
  application:
    name: order-server   # eureka的服务名称
eureka:
  client:
    service-url:     #eureka地址信息
      defaultZone: http://127.0.0.1:10086/eureka

idea同时启动两个服务器

在这里插入图片描述

通过注册中心的方式进行远程调用

在这里插入图片描述

负载均衡

  • Ribbon @LoadBalanced
    整体流程
    发送请求,负载均衡拦截请求(RibbonLoadBanlancerClient),拦截器获取服务名称,(DynamiscServiceListLoadBalancer)根据服务名称去Eureka拉取服务列表,拉取列表后,IRule做出负载均衡的选择,选择服务后,附近均衡拦截器(RibbonLoadBanlancerClient)修改url(也就是将注册名称换位真实地址),发起请求
    在这里插入图片描述

IRule 接口 决定负载均衡策略的接口

  • 定义负载均衡规则 随机调用

  • 方法1.配置全局 ->配置类中配置bean

    @Bean  // 调整为随机-> 全局
    public IRule randomRule(){
        return new RandomRule();
    }
  • 方法2.配置单个微服务 -> 根据名称指定负载均衡的策略 -> yaml文件
userservice: # 给某个微服务配置负载均衡规则,这里是userservice服务
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule # 负载均衡规则

Ribbon -> 饥饿加载 ->项目启动的一刻完成服务加载

  • Ribbon采用的是懒加载,第一次访问才会创建LoadBalanceClient,请求时间就会很长
  • 采用饥饿加载
ribbon:
  eager-load:
    enabled: true  #开启饥饿加载
    clients: userservice   #集合,可以配置多个服务
     # - xxx
     # - xxx

Nacos 注册中心

1.安装
2.bin目录下启动命令行 输入 startup.cmd -m standalone
3.启动成功输入ip进入

使用Nacos

1.父工程加入pom依赖

            <!--nacos的服务管理依赖-->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>2.2.5.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

2.子工程加入Pom依赖

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

3.子工程修改yml文件

server:
  port: 8080
spring:
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 #nacos服务地址
  application:  
    name: orderserver   #设置nacos名称

4.访问http://192.168.1.8:8848/nacos/index.htm 账户密码均为 nacos
5.负载均衡策略为:轮循 (一个服务器一个)
在这里插入图片描述

集群

在这里插入图片描述

spring:
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 #nacos服务地址
        cluster-name: HZ  #集群名称

1.一级是服务 例如:userservice 用户模块
2.二级是集群 例如:模块再同一个地方部署了多个,称之为xx集群
3.三级是实例 多个实例,称之为集群 例如:将杭州机房部署了用户模块,部署了多个称之为杭州集群

Nacos负载均衡的策略

1.优先选择同集群服务实例列表
2.本地集群找不到提供者,采取其他集群寻找,并且会报警告
3.确定了实例列表,再采用随机负载均衡的策略挑选实例

userservice:
  ribbon:
    NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule # 负载均衡规则 -> 优先选择本地集群,
spring:
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 #nacos服务地址
        cluster-name: HZ   #集群名称

在这里插入图片描述

根据权重负载均衡

1.Nacos控制太可以设置实例权重值,0-1之间
2.集群中的多个实例,权重越高被访问的频率也就越高
3.权重设置为0则不会被访问
在这里插入图片描述

NAcos 环境隔离

  • namespace: id作为环境 #环境名称
  • 每个namespace都有唯一的id
  • 不同namespace下的服务不可使用
  • namespace: 18ada1e3-9776-4110-8e95-89aaf1d03ee0 #dev环境
    在这里插入图片描述

Nacos与Eureka的共同点

  • 都支持服务注册和服务拉取
  • 都支持服务提供者心跳方式进行监控检测

Nacos与Eureka的区别

  • Nacos支持服务端主动检测提供者的状态,临时实例采用心跳模式,非临时实例采用主动检测模式
  • 临时实例心跳不正常会被剔除,非临时实例不会被剔除,Nacos会向非临时实例发送信息查看是否恢复
  • Nacos支持服务列表变更的消息推送模式,服务列表更新更及时
  • Nacos集群采用AP方式,当集群中存在非临时实例时,采用CP模式,Eureka采用AP方式

临时实例为默认,修改为非临时实例 -> ephemeral: false

spring:
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 #nacos服务地址
        cluster-name: HZ   #集群名称
        ephemeral: false   #是否是临时实例
        namespace: e770a314-ca1f-40d9-a25d-6607825b1866  #dev环境

Nacos配置管理

  • 配置管理->将核心配置文件配置到配置管理中,启动服务的时候就会自动拉取这些服务

在这里插入图片描述

步骤如下
在这里插入图片描述

实现步骤

  1. 加入注解
		<dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>
  1. 创建bootstrap.yml 启动读取时,优先级最高
spring:
  application:
    name: userservice  #服务名称
  profiles:
    active: dev # 环境
  cloud:
    nacos:
      server-addr: localhost:8848
      config:
        file-extension: yaml
        namespace: 18ada1e3-9776-4110-8e95-89aaf1d03ee0   #dev环境

在这里插入图片描述

热更新 修改了Nacos的配置,不用重新启动,自动更新

  • @RefreshScope Controller上面加@RefreshScope 注解
@RefreshScope
public class UserController {
}
  • 声明配置类
@Data
@Component   // bean注入
@ConfigurationProperties(prefix = "pattern")
public class PatternProperties {

    public String dateformat;
}


   @Autowired
    PatternProperties patternProperties;


    @GetMapping("/now")
    public String now(){   // 根据配置信息进行返回
        return LocalDateTime.now().format(DateTimeFormatter.ofPattern(patternProperties.getDateformat()));
    }

在这里插入图片描述

多环境配置共享

  • 优先级
    设置相同的名称,访问,得知当前自己的环境nacos配置最大。
    自己当前环境的nacos配置 > 当前环境nacos的共享配置 > 本地配置
    在这里插入图片描述

  • 多环境共享配置 不用的环境下(dev、Test等),相同的[服务名称].yaml,都可以访问这个文件

  • 在这里插入图片描述

在这里插入图片描述

Nacos集群

  • nginx负载均衡搭建Nacos集群服务,项目启动时,消费者访问Nacos地址端口,nginx进行负载均衡,分发请求到集群

Feign远程调用

Feign使用声明式,基于Springmvc的注解声明远程调用的信息

  • 服务名称:userservice
  • 请求方式:GET
  • 请求路径:/user/{id}
  • 请求参数:Long id
  • 返回值类型: User

1.引入依赖

<!--        引入依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

2.启动类加注解

@EnableFeignClients
public class UserApplication {
    public static void main(String[] args) {
        SpringApplication.run(UserApplication.class, args);
    }
}

3.编写客户端,做接口声明

@FeignClient("userservice")  //服务者名称
public interface UserClient {

    @GetMapping("/user/{id}")  // 访问路径
    User findyById(@PathVariable("id")Long id);  //请求参数

}

4.注入bean,并且调用方法,实现远程调用

   @Autowired
   private UserClient userClient;

    @GetMapping("{orderId}")
    public Order queryOrderByUserId(@PathVariable("orderId") Long orderId) {
        // 1.根据id查询订单
        Order order = orderService.queryOrderById(orderId);
        // 2.用feign远程调用
        User user = userClient.findyById(order.getUserId());
        order.setUser(user);
        return order;
    }

Feign自定义配置

在这里插入图片描述

配置日志

    1. yaml的形式
feign:
  client:
    config:
      default:   #default 代表全局  userservice 代表某个服务开启日志
        loggerLevel: FULL
    1. 注解的形式
启动类上代表全局
@MapperScan("cn.itcast.order.mapper")
@SpringBootApplication
@EnableFeignClients(defaultConfiguration = DefaultFeignConfiguration.class)   // 代表全局
public class OrderApplication {
}



服务声明类上,代表此服务
@FeignClient(value = "userservice" , configuration =  DefaultFeignConfiguration.class)  //代表单个服务
public interface UserClient {


    @GetMapping("/user/{id}")  // 访问路径
    User findyById(@PathVariable("id")Long id);  //请求参数


}

Feign的性能优化

1.使用HttpClient或者OkHttp代替URLCtion
2.配置文件开启HttpClient功能设置连接参数

1.日志级别尽量用basic

1.引入依赖

<!--httpClient的依赖 -->
<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-httpclient</artifactId>
</dependency>
2.yaml配置

```java
feign:
  client:
    config:
      default: # default全局的配置
        loggerLevel: BASIC # 日志级别,BASIC就是基本的请求和响应信息
  httpclient:
    enabled: true # 开启feign对HttpClient的支持
    max-connections: 200 # 最大的连接数
    max-connections-per-route: 50 # 每个路径的最大连接数

最佳实践

    1. 让controller接口和FeignClient集成同一个接口
    1. 将FeignClient、Pojo、feign的默认配置都定义到一个项目中,消费者引入jay包,进行使用

操作步骤:
1.新建model引入依赖
2.添加jar包

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

将代码抽离出来,放到fegin-api中
在这里插入图片描述
3.服务消费者引入fegin-api的jar包
在这里插入图片描述
4.扫描 fegin-api 下的所有的包
第一种方法:
在这里插入图片描述第二种方法:
在这里插入图片描述

网关

服务者将信息注册到那cos中,用户发送请求,网关接收请求,根据路由规则查看请求是否符合条件,符合条件去Nacos拉取对应的服务请求,再进行负载均衡的向该服务发送请求

  • 身份认证和权限校验 (类似于拦截器)
  • 服务路由(分发在指定的服务)、负载均衡
  • 请求限流

gateway
属于响应式编程
zuul
属于阻塞式编程

搭建网关

1.新建model
在这里插入图片描述
引入依赖

    <dependencies>
        <!--网关-->
        <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>
    </dependencies>

配置路由:

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-server
          uri: lb://orderserver # 路由的目标地址 lb就是负载均衡,后面跟服务名称
          predicates: # 路由断言,也就是判断请求是否符合路由规则的条件,符合规则就会代理到路由中
            - Path=/order/** # 这个是按照路径匹配,只要以/user/开头就符合要求

在这里插入图片描述

断言工厂

  • 读取用户定义的断言规则,解析出来,查看请求是否符合规则
  • path=/user/** 路径以user开头的就认为符合规则
    在这里插入图片描述
    在这里插入图片描述

路由过滤器

  • 对微服务进入网关的请求和微服务返回的响应做处理

  • 对路由的请求或响应加工
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/开头就符合要求
          filters:
            - AddRequestHeader=Truth, Itcast is freaking awesome!
        - id: order-server
          uri: lb://orderserver # 路由的目标地址 lb就是负载均衡,后面跟服务名称
          predicates: # 路由断言,也就是判断请求是否符合路由规则的条件,符合规则就会代理到路由中
            - Path=/order/** # 这个是按照路径匹配,只要以/user/开头就符合要求
      default-filters:  #配置全局
#        - AddRequestHeader=Truth, Itcast is freaking awesome!

   /**
     * 路径: /user/110
     *
     * @param id 用户id
     * @return 用户
     */
    @GetMapping("/{id}")
    public User queryById(@PathVariable("id") Long id ,@RequestHeader(value = "truth" , required = false) String truth) {
        System.out.println("truth:="+truth);
        return userService.queryById(id);
    }

在这里插入图片描述

Gateway 通过代码实现过滤规则

  • 对所有的路由都生效,并且可以自定义逻辑
  • 定义GlobaFilter的步骤:
  • 1.实现GlobalFilter接口
  • 2.编写处理逻辑
  • 3.使用注解 : @Component //定义组件 / @Order(-1) //执行顺序
package cn.itcast.gateway;

import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

@Component  //定义组件
@Order(-1)  //执行顺序
public class AuthorizeFilter implements GlobalFilter {

    /**
     * ServerWebExchange:获取请求参数
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 1.获取请求参数
        ServerHttpRequest request = exchange.getRequest();
        // 2.获取请求种的 authorization
        MultiValueMap<String, String> queryParams = request.getQueryParams();
        // 根据authorization获取对应的值
        String authorization = queryParams.getFirst("authorization");
        // 3.判断参数是否等于admin
        if ("admin".equals(authorization)){
        // 4.是  放行
            return chain.filter(exchange);
        }
        // 5.否  拦截
        // 5-1.设置状态码
        exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
        return exchange.getResponse().setComplete();
    }

}

过滤器执行顺序

  • order值越小,优先级越高
  • 当order值一样时,顺序是defaultFilter > 局部的路由过滤器 > 全局过滤
    在这里插入图片描述

网关的跨域问题处理

  • 前端发送的ajax请求与服务器域名端口不一致
  • 例如: http://1.1.1.1:80 发送ajax请求到 http://1.1.1.2:81
  • yml配置CORS
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 # 这次跨域检测的有效期
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值