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

SpringBoot微服组件

语雀完整版:

https://www.yuque.com/g/mingrun/embiys/tg4ykv/collaborator/join?token=qlyX7pFpOkClrFRn&source=doc_collaborator# 《SpringBoot&微服组件》

SpringBoot&微服组件

SpringBoot

自动配置原理

常用注解

  1. 组合注解
    • 被其它注解 注解的注解叫做组合注解
    • 元注解 注解其它注解的注解
  1. @Value
    • 相当于Bean标签中的 property标签
    • 取值可以是
      • 字面量
      • ${key} 从环境变量 或者全局配置文件中获取值
      • #{SpEL}
  1. @ConfigurationProperties 【SpringBoot 提供】
    • 从配置文件中 注入多个值
    • 示例
@Component 
@ConfigurationProperties(prefix = "person") // 获取person开头的配置
public class Person { private String name; private Integer age; private String sex; 
}

  1. @Import 【Spring 提供】
    • 作用:导入普通的Java类,并将其声明为大的Bean
    • 直接导入普通的 Java 类
public class Circle { public void sayHi() { System.out.println("Circle sayHi()"); } 
}

@Import({Circle.class}) 
@Configuration 
public class MainConfig { 
}

    • 配合自定义的 ImportSelector
      • 该接口中只有一个 selectImports 方法,用于返回全类名数组。所以利用该特性我们可以给容器动态导入 N 个 Bean。
public class MyImportSelector implements ImportSelector { @Override public String[] selectImports(AnnotationMetadata annotationMetadata) { return new String[]{"annotation.importannotation.waytwo.Triangle"}; } 
}
@Import({Circle.class,MyImportSelector.class}) 
@Configuration 
public class MainConfigTwo {
}
    • 配合 ImportBeanDefinitionRegistrar
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { @Override public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) { RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(Rectangle.class); // 注册一个名字叫做 rectangle 的 bean beanDefinitionRegistry.registerBeanDefinition("rectangle", rootBeanDefinition); } 
}

@Import({Circle.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class}) 
@Configuration 
public class MainConfigThree {
}

  1. @Conditional 【Spring提供】
    • 使用该注解,可以在特定条件下才启用一些配置
    • 案例
public class ConditionBean { public void sayHi() { System.out.println("ConditionBean sayHi()"); } 
}

public class MyCondition implements Condition { @Override public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) { //这里先直接返回truereturn true; } 
}

@Configuration 
@Conditional(MyCondition.class) 
public class ConditionConfig { @Bean public ConditionBean conditionBean(){ return new ConditionBean(); } 
}


然后测试,就会发现ConditionBean已经在容器中了
Spring提供的常见的Condition

SpringBoot 启动过程

  1. 当启动springboot应用程序的时候, 会先创建SpringApplication的对象, 在对象的构造方法中会进行某些参数的初始化工作,最主要的是判断当前应用程序的类型以及初始化器和监听器,在这个过程中会加载整个应用程序中的spring.factories文件,将文件的内容放到缓存对象中,方便后续获取。
  1. SpringApplication对象创建完成之后, 开始执行run方法,来完成整个启动,启动过程中最主要的有两个方法,第一个叫做prepareContext, 第二个叫做refreshContext,在这两个关键步骤中完整了自动装配的核心功能,前面的处理逻辑包含了上下文对象的创建,banner的打印, 异常报告期的准备等各个准备工作,方便后续来进行调用。
  1. 在prepareContext方法中主要完成的是对上下文对象的初始化操作,包括了属性值的设置,比如环境对象,在整个过程中有-个非常重要的方法,叫做load, load主要完成一 件事,将当前启动类做为一个beanDefinition注册到registry中,方便后续在进行BeanFactoryPostProcessor调用执行的时候, 找到对应的主类,来完成@SpringBootApplicaiton,@EnableAutoConfiguration等注解的解析工作
  1. 在refreshContext方法中会进行整个容器刷新过程, 会调用中spring中的refresh方法, refresh中有13个非常关键的方法,来完成整个spring应用程序的启动,在自动装配过程中,会调用invokeBeanFactoryPostProcessor方法,在此方法中主要是对ConfigurationClassPostProcessor类的处理, 这次是BFPP的子类也是BDRPP的子类,在调用的时候会先调用BDRPP中的postProcessBeanDefinitionRegistry方法,然后调用postProcessBeanFactory方法,在执行postProcessCeanDefinitionRegistry的时候回解析处理各种注解,包含@PropertySource,@ComponentScan,@ComponentScans, @Bean,@lmport等注解,最主要的是@lmport注解的解析
  1. 在解析@Import注解的时候,会有一个getlmports的方法, 从主类开始递归解析注解,把所有包含
    @Import的注解都解析到,然后在processlmport方法中对Import的类进行分类, 此处主要识别的时候
    AutoConfigurationlmportSelect归属于ImportSelect的子类,在后续过程中会调用
    deferredlmportSelectorHandler中的process方法,来完整EnableAutoConfiguration的加载。

SpringBoot 自动配置过程

[SpringBoot自动配置原理.png](D:\JAVA\思维图\05-1 Spring一家人\SpringBoot自动配置原理.png)

这样讲 SpringBoot 自动配置原理,你应该能明白了吧 - 掘金 (juejin.cn)

聊聊 SpringBoot 自动装配原理 - 掘金 (juejin.cn)

  1. 概述
    • 没有SpringBoot的情况下,如果要在项目中使用redis,就要加第三方依赖,然后手动配置,而在springboot中直接引入一个 starter即可
  1. 流程概述:进入@SpringBootApplication注解,就会看到@EnableAutoConfiguration,再进去有两个步骤
    • 第一个步骤是加载 启动类和启动类所在的包和子包的所有Bean 到容器
    • 第二个步骤是到 META-INF/spring.factories下加载所有的EnableAutoConfiguration到Spring容器中
  1. 其它总结
    • SpringBoot启动会加载大量的自动配置类。
    • 我们看需要的功能有没有SpringBoot默认写好的自动配置类。
    • 我们再来看这个自动配置类中到底配置了那些组件(只要我们要用的组件有,我们就不需要再来配置了)。
    • 给容器中自动配置类添加组件的时候,会从properties类中获取某些属性。我们就可以在配置文件中指定这些属性的值。
      • xxxAutoConfiguration:自动配置类给容器中添加组件。
      • xxxProperties:封装配置文件中相关属性。
  1. 自定义Starter流程
    • 引入spring-boot-starter依赖
    • 创建一个自己的AutoConfiguration(它的作用就是加载配置,然后返回Bean)

    • 然后在你这个工程的 resources 包下创建META-INF/spring.factories文件

    • 然后就可以在其它工程引用这个starter了

  1. SPI(Service Provider Interface)
    • 高级开发必须理解的Java中SPI机制 - 简书 (jianshu.com)
      深入理解SPI机制 - 简书 (jianshu.com)
    • 是一种服务发现机制,通过在ClassPath路径下的META-INF/services文件夹查找文件,自动加载文件里所定义的类。
    • 实现步骤
      • 定义一个 接口和它的实现类们
      • 在classpath下面加一个文件,文件名字是接口的全限定类名,内容是实现类的全限定类名

      • 调用代码
public static void main(String[] args) {    //SPIService是上面所说的接口 有两个实现类//调用方式一 使用ServiceIterator<SPIService> providers = Service.providers(SPIService.class);while(providers.hasNext()) {SPIService ser = providers.next();ser.execute();}System.out.println("--------------------------------");//调用方式二 使用ServiceLoaderServiceLoader<SPIService> load = ServiceLoader.load(SPIService.class);Iterator<SPIService> iterator = load.iterator();while(iterator.hasNext()) {SPIService ser = iterator.next();ser.execute();}
}

      • ServiceLoader,其中serviceLoader先判断缓存中 是否有已经实例化好的对象,如果没有就读取 META-INF/services/下的配置(可以扫描多个jar包路径下的),通过反射方法Class.forName()加载类对象,并用instance()方法将类实例化,然后再缓存(一个LinkedHashMap<String,S>类型)
    • SPI优缺点
      • 优点是 解耦合,与调用者分离了,而且调用者不用再关心具体的实现类 在什么路径,比如JDBC,之前是Class.forName("com.mysql.jdbc.Driver"),后来就直接使用 DriveManger
      • 缺点就是如果用 ServiceLoader,遍历的时候,会把全部的实现都加载一遍

微服组件

Eureka

  1. 概述
    • 主要包括两个组件 Eureka Server和Eureka client
  1. 流程流程说明
    (1)服务提供者集成Eureka客户端,启动时,Eureka客户端发送注册请求到Eureka服务端;
    (2)Eureka客户端每30秒发送一次续约请求到Eureka服务端;
    (3)若Eureka服务端超过90秒未收到服务提供者的续约请求,则Eureka服务端会将其从服务列表中踢除;
    (4)服务消费者集成Eureka客户端,启动时,Eureka客户端同样会发送注册请求到Eureka服务端;
    (5)服务消费者中,Eureka客户端每隔30秒,会从Eureka服务端获取服务实例列表,其中,首次是全量查询,后续为增量查询;获取到实例列表后,Eureka客户端会将其写入到本地缓存中;
    (6)服务消费者调用服务提供者时,Eureka会总本地缓存获取对应的实例,并进行接口调用。
  1. 多级缓存机制

    • 拉取注册表
      首先从ReadOnlyCacheMap里查缓存的注册表。若没有,就找ReadWriteCacheMap里缓存的注册表。如果还没有,就从内存中获取实际的注册表数据。
    • 注册表发生变更
      会在内存中更新变更的注册表数据,同时过期掉ReadWriteCacheMap。此过程不会影响ReadOnlyCacheMap提供人家查询注册表。
      一段时间内(默认30秒),各服务拉取注册表会直接读ReadOnlyCacheMap 30秒过后,Eureka Server的后台线程发现ReadWriteCacheMap已经清空了,也会清空ReadOnlyCacheMap中的缓存 下次有服务拉取注册表,又会从内存中获取最新的数据了,同时填充各个缓存。
    • 多级缓存机制的优点是什么?
      尽可能保证了内存注册表数据不会出现频繁的读写冲突问题。并且进一步保证对Eureka Server的大量请求,都是快速从纯内存走,性能极高。

Ribbon

Spring-Cloud之Ribbon原理剖析 - 起岸星辰 - 博客园 (cnblogs.com)

  1. 内置的负载均衡策略
    • RoundRobinRule:直接轮询的方案;即每次从server list中依次选择。
    • AvailabilityfileringRule:根据服务器可用性来决定;比如某个服务器的并发请求过高,那么此时ribbon就会绕过不再访问;同时如果3次连接失败就会等待30秒后再次访问;如果不断失败,那么等待时间会不断变长,如果某个服务器的并发请求太高了,那么会绕过去,不再访问。
    • WeightedResponseTimeRule:根据权重来分配;每个服务器都可以有权重,权重高就优先访问,如果某个服务器响应时间比较长,那么权重就会降低,减少访问。
    • ZoneAvoidanceRule:根据区域和服务器来进行负载均衡,也就是根据机房来分配,里面再使用轮询的方式。默认的就是这个
    • BestAvailableRule:忽略连接失败的服务器,同时尽量找并发比较低的服务器来请求。
    • RandomRule:随机选择一个。
    • RetryRule:在轮询的方案上增加重试机制;即通过轮询的方式选择一个服务器请求,在失败的时候会重新再找一个重试。
  1. 过程
    • Ribbon主要就是 通过服务名拿到服务列表,然后再根据负载均衡策略选择一个服务,通过拦截器设置请求地址
    • Iping机制:ribbon的IPing机制,就是每隔30秒去检查注册表中的服务 是否可用,不可用就移除
      其中,Ribbon获取注册表是每30秒从Eureka Client拷贝一次注册表
  1. 客户端负载均衡与服务端负载均衡

Fegin

  1. 实现思路
    • 在类上标上注解(注解上包含要调用的接口信息),之后就会根据注解封装好请求信息,然后用ribbon获取真实的地址信息,请求发出后 获得结果再发序列化交给对象处理
  1. 核心机制
    [Fegin核心机制.png](D:\JAVA\思维图\05-1 Spring一家人\微服组件\Fegin核心机制.png)

Nacos

阿里面试这样问:Nacos配置中心交互模型是 push 还是 pull ?(原理+源码分析) (qq.com)

  1. 配置中心
    • 作用:对配置进行统一管理,修改配置后可以动态感知,无需重启
    • 客户端与配置中心的交互:推与拉
      • 推:与客户端建立长连接,一有变动立刻推送,缺点就是可能会因为网络问题出现假死,连接状态正常却无法通信,这就需要心跳机制来保证连接的可用性
      • 拉:客户端轮询 向配置中心拉取数据,比如每隔3s一次,但这样做不到实时性,而且可能会服务端产生压力
        • 长轮询与短轮询
          • 短轮询:每隔几秒钟拉取一次配置,而配置一般是不修改的,而且这种方式更新会有延迟
          • 长轮询:客户端请求过来后,如果配置变更,那就立刻响应,如果没有变更,那就直到超时时间过后在响应,然后客户端再发起下次的长连接

    • Nacos采用的就是 客户端拉的方式,而且是长轮询
    • 配置中心的核心概念
      • dataId是一份配置文件的id,key value格式存储,value是配置文件的内容
      • groupId分组,用于一个环境下的不同分支的配置隔离
      • nameSpace:dev、test这种不同的环境
  1. 架构设计

    • 客户端控制台 将自己的配置推送到配置中心,配置中心会见配置持久化在MySQL中
    • 然后客户端获取最新配置的时候 向服务端发起长轮询请求,获取配置后也会在本地存一份,有限读取
http://www.dtcms.com/a/279138.html

相关文章:

  • 毫米波雷达在转弯时将静止目标识别为运动目标的原因
  • JavaSE-8-多态
  • python 双下划线开头函数
  • 【字节跳动】数据挖掘面试题0017:推荐算法:双塔模型,怎么把内容精准地推送给用户
  • ATE - Force模式和Meas模式
  • AI Agent vs SaaS:企业服务产品正迈向“智能中枢”阶段
  • Linux中使用云仓库上传镜像和私库制作Registry
  • 算法-练习题
  • 【牛客刷题】小红的数字删除
  • 可达性统计(拓扑排序模板,bitset)
  • 【算法】贪心算法:最大数C++
  • Linux 音频的基石: ALSA
  • 【云服务器安全相关】如何使用 `ping` 命令排查云服务器网络连接问题
  • javascript自执行函数
  • Retinex视网膜算法(SSR、MSR、MSRCR)
  • DNS重绑定
  • 纯净系统清理工具,告别卡顿烦恼
  • iOS高级开发工程师面试——RunTime
  • 构建完整工具链:GCC/G++ + Makefile + Git 自动化开发流程
  • 数字影像产业新机遇 入驻国际数字影像产业园享151项服务
  • 【人工智能】通过 Dify 构建智能助手
  • Day34 Java方法05 可变参数
  • JavaScript中Object.defineProperty的作用和用法以及和proxy的区别
  • 优化菜品呈现:让菜品自己 “开口” 求传播
  • 【ASP.NET Core】内存缓存(MemoryCache)原理、应用及常见问题解析
  • 我的Qt八股文笔记2:Qt并发编程方案对比与QPointer,智能指针方案
  • 电气安全监测系统:筑牢电气安全防线
  • DAOS系统架构-Container
  • 壹[1],异步与多线程
  • 美联储降息趋缓叠加能源需求下调,泰国证券交易所新一代交易系统架构方案——高合规、强韧性、本地化的跨境金融基础设施解决方案