【Java】【系列篇】【Spring源码解析】【三】【体系】【BeanDefinition体系】

news2024/10/6 22:18:50

整体结构图

image-20230111110224787

1. BeanDefinition 用于保存 Bean 的相关信息,包括属性、构造方法参数、依赖的 Bean 名称及是否单例、延迟加载等,
它是实例化 Bean 的原材料,Spring 就是根据 BeanDefinition 中的信息实例化 Bean2. 我们获取对象的方式一般有两种,一种是手动直接 new;另一种是交给 Spring 管理,Spring 将管理的对象称之为 Bean,
容器会先实例化 Bean,然后自动注入,实例化的过程就需要依赖 BeanDefinition。
过程:BeanDefinition----通过一系列加工--->Bean

BeanDefinition

image-20230113140022585

作用

  • 存储属性 : 基于接口 AttributeAccessor 实现
  • 存储元数据配置 : 基于 BeanMetadataElement 实现
  • 描述类的信息 : 包括Bean名称 , Primary 属性 , priority 配置 等等

总结其实就是一句话 : BeanDefinition 主要承载了Bean的元数据信息 ,同时描述了Bean在Spring体系中的加载方式 , 容器通过 BeanDefinition 中的配置来加载一个Bean

解析

BeanDefinition主要继承了两个接口,分别是AttributeAccessor,BeanMetadataElement;AttributeAccessor先不讲(AbstractBeanDefinition那里讲),我们先看看BeanMetadataElement,如图:

image-20230113144134582

主要提供了获取源的方法,而什么是source呢?如图,这是包路径扫描时,将扫描的数据封装成ScannedGenericBeanDefinition的一部分操作,准备将获取到的source放入到BeanDefinition里:

image-20230113141303201

方法注释

属性

// 单例、原型标识符
String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;
String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;
// 标识 Bean 的类别,分别对应 用户定义的 Bean、来源于配置文件的 Bean、Spring 内部的 Bean
int ROLE_APPLICATION = 0;
int ROLE_SUPPORT = 1;
int ROLE_INFRASTRUCTURE = 2;

方法

Bean的父类名称

void setParentName(@Nullable String parentName);
@Nullable
String getParentName();

Bean的 className

void setBeanClassName(@Nullable String beanClassName);
@Nullable
String getBeanClassName();

Bean的作用域

void setScope(@Nullable String scope);
@Nullable
String getScope();

Bean构造方法参数值、所有属性

ConstructorArgumentValues getConstructorArgumentValues();
default boolean hasConstructorArgumentValues() {
    return !getConstructorArgumentValues().isEmpty();
}
MutablePropertyValues getPropertyValues();
default boolean hasPropertyValues() {
    return !getPropertyValues().isEmpty();
}

Bean的类别

类别对应上面的三个属性值

void setRole(int role);
int getRole();

对bean定义的可读描述

void setDescription(@Nullable String description);
@Nullable
String getDescription();

Bean是否是单例、是否是非单例、是否是抽象的

boolean isSingleton();
boolean isPrototype();
boolean isAbstract();

该bean定义来自的资源的描述(用于在出现错误时显示上下文)

@Nullable
String getResourceDescription();

原始Bean定义

@Nullable
BeanDefinition getOriginatingBeanDefinition();

Bean是否懒加载(@Lazy)

void setLazyInit(boolean lazyInit);
boolean isLazyInit();

Bean所依赖的其它Bean 名称(@DependsOn)

void setDependsOn(@Nullable String... dependsOn);
@Nullable
String[] getDependsOn();

Bean是否可以自动注入(@Autowired)

只对 @Autowired 注解有效

void setAutowireCandidate(boolean autowireCandidate);
boolean isAutowireCandidate();

当前Bean是否为主要候选 Bean (@Primary)

当同一个接口有多个实现类时,通过该属性来配置某个 Bean 为主候选 Bean。

void setPrimary(boolean primary);
boolean isPrimary();

创建该Bean的工厂类

void setFactoryBeanName(@Nullable String factoryBeanName);
@Nullable
String getFactoryBeanName();

创建该Bean的工厂方法

void setFactoryMethodName(@Nullable String factoryMethodName);
@Nullable
String getFactoryMethodName();

初始化方法名称

void setInitMethodName(@Nullable String initMethodName);
@Nullable
String getInitMethodName();

销毁方法名称

void setDestroyMethodName(@Nullable String destroyMethodName);
@Nullable
String getDestroyMethodName();

获取*

ResolvableType getResolvableType();

AnnotatedBeanDefinition

作用

这个接口主要提供了对注解的支持

方法解析

获取注释元数据(以及基本类元数据)

AnnotationMetadata getMetadata();

获取此bean定义的工厂方法的元数据(如果有的话)

@Nullable
MethodMetadata getFactoryMethodMetadata();

AbstractBeanDefinition

image-20230113152733605

解析

AbstractBeanDefinition基本上实现了BeanDefinition所有方法,除了这两个:

image-20230113154451792

可以说,AbstractBeanDefinition重中之重,基本上所有的BeanDefinition都直接间接的继承了它。我们再看,除了BeanDefinition,AbstractBeanDefinition还继承了BeanMetadataAttributeAccessor类,这个类继承了AttributeAccessorSupport实现了BeanMetadataElement:

image-20230113154839453

如果你已经阅读了BeanDefinition那部分的内容,那么你大概也知道了BeanMetadataElement的作用,以及source的样子,所以我们主要讲一下AttributeAccessorSupport这个类,AttributeAccessorSupport是唯一实现了AttributeAccessor接口的类,具有了操作属性的功能,并且里面拥有一个map,用于存放属性:

image-20230113155708131

而属性具体在什么时候用到了呢?目前就我了解的一个作用就是存放标志位,用于标识做过了哪些操作。例如下面是注解 载入BeanDefinition时部分代码,红框部分,就是从属性map里面获取加载标识位,判断BeanDefinition是否有加载过:

image-20230113160055520

像调用ConfigurationClassUtils#checkConfigurationClassCandidate(校验Bean是否是配置类)时,在期间就又加了一些标志位:

image-20230113154241113

属性解析

常量

//默认的SCOPE,默认是单例
public static final String SCOPE_DEFAULT = "";

// 自动装配的一些常量
public static final int AUTOWIRE_NO = AutowireCapableBeanFactory.AUTOWIRE_NO;
public static final int AUTOWIRE_BY_NAME = AutowireCapableBeanFactory.AUTOWIRE_BY_NAME;
public static final int AUTOWIRE_BY_TYPE = AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE;
public static final int AUTOWIRE_CONSTRUCTOR = AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR;
@Deprecated
public static final int AUTOWIRE_AUTODETECT = AutowireCapableBeanFactory.AUTOWIRE_AUTODETECT;

//检查依赖是否合法,在本类中,默认不进行依赖检查
public static final int DEPENDENCY_CHECK_NONE = 0; // 不进行检查
public static final int DEPENDENCY_CHECK_OBJECTS = 1; //如果依赖类型为对象引用,则需要检查
public static final int DEPENDENCY_CHECK_SIMPLE = 2; //对简单属性的依赖进行检查
public static final int DEPENDENCY_CHECK_ALL = 3; //对所有属性的依赖进行检查

//若Bean未指定销毁方法,容器应该尝试推断Bean的销毁方法的名字,目前来说,推断的销毁方法的名字一般为close或是shutdown
//(即未指定Bean的销毁方法,但是内部定义了名为close或是shutdown的方法,则容器推断其为销毁方法)
public static final String INFER_METHOD = "(inferred)";

属性

基本属性

//Bean的class对象或是类的全限定名
@Nullable
private volatile Object beanClass;
//默认的scope是单例
@Nullable
private String scope = SCOPE_DEFAULT;
//默认不为抽象类
private boolean abstractFlag = false;
//默认不进行自动装配
private boolean lazyInit = false;
//默认不是懒加载
private int autowireMode = AUTOWIRE_NO;
//默认不进行依赖检查
private int dependencyCheck = DEPENDENCY_CHECK_NONE;
// @@DependsOn 默认没有
@Nullable
private String[] dependsOn;
// autowire-candidate属性设置为false,这样容器在查找自动装配对象时,将不考虑该bean,
// 备注:并不影响本身注入其它的Bean
private boolean autowireCandidate = true;
// 默认不是首选的
private boolean primary = false;
用于记录Qualifier,对应子元素qualifier
private final Map<String, AutowireCandidateQualifier> qualifiers = new LinkedHashMap<>(0);
//是否是合成类(是不是应用自定义的,例如生成AOP代理时,会用到某些辅助类,这些辅助类不是应用自定义的,这个就是合成类)
//创建AOP时候为true
private boolean synthetic = false;
//Bean的角色,为用户自定义Bean
private int role = BeanDefinition.ROLE_APPLICATION;
// Bean的描述信息
@Nullable
private String description;
// 这个Bean哪儿来的
@Nullable
private Resource resource;

构造相关

//记录构造函数注入属性,对应bean属性constructor-arg
@Nullable
private ConstructorArgumentValues constructorArgumentValues;
//Bean属性的名称以及对应的值,这里不会存放构造函数相关的参数值,只会存放通过setter注入的依赖
@Nullable
private MutablePropertyValues propertyValues;
//方法重写的持有者,记录lookup-method、replaced-method元素  @Lookup等
@Nullable
private MethodOverrides methodOverrides;

方法相关

//init函数的名字
@Nullable
private String initMethodName;
//destory函数的名字
@Nullable
private String destroyMethodName;
//是否执行init-method,程序设置
private boolean enforceInitMethod = true;
private boolean enforceDestroyMethod = true;

工厂相关

//我理解为通过这个函数的逻辑初始化Bean,而不是构造函数或是工厂方法(相当于自己去实例化,而不是交给Bean工厂)
@Nullable
private Supplier<?> instanceSupplier;
//是否允许访问非public方法和属性,应用于构造函数、工厂方法、init、destroy方法的解析 默认是true,表示啥都可以访问
private boolean nonPublicAccessAllowed = true;
// 是否以一种宽松的模式解析构造函数,默认为true(宽松和严格体现在类型匹配上)
private boolean lenientConstructorResolution = true;
//工厂类名(注意是String类型,不是Class类型) 对应bean属性factory-method
@Nullable
private String factoryBeanName;
//工厂方法名(注意是String类型,不是Method类型)
@Nullable
private String factoryMethodName;

ChildBeanDefinition

已经废弃了,被GenericBeanDefinition替代了,不多赘述了。

GenericBeanDefinition

解析

GenericBeanDefinition在继承AbstractBeanDefinition的基础上,实现了getParentName和setParentName这两个方法,可以设置父类BeanDefinition的名称:

image-20230113161237897

一般来说,这个类是用于XML加载Bean定义信息时,会将读取到的数据封装成GenericBeanDefinition,PS:你首先要知道xml方式是通过XmlBeanDefinitionReader解析器加载xml里的所有数据的。

加载路径:

XmlBeanDefinitionReader#loadBeanDefinitions(EncodedResource encodedResource)
	-->doLoadBeanDefinitions(InputSource inputSource, Resource resource)
	-->registerBeanDefinitions(Document doc, Resource resource)
-->DefaultBeanDefinitionDocumentReader#registerBeanDefinitions(Document doc, XmlReaderContext readerContext)
	-->doRegisterBeanDefinitions(Element root)
	-->parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate)
	-->parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate)
	-->processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate)
-->BeanDefinitionParserDelegate#parseBeanDefinitionElement(Element ele)
	-->parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean)
	-->parseBeanDefinitionElement(Element ele, String beanName, @Nullable BeanDefinition containingBean)
	-->createBeanDefinition(@Nullable String className, @Nullable String parentName)
-->BeanDefinitionReaderUtils#createBeanDefinition(@Nullable String parentName, @Nullable String className, @Nullable ClassLoader classLoader)

最终,如图,创建了GenericBeanDefinition:

image-20230113162902306

RootBeanDefinition

作用

主要在 Bean 实例化时使用,为了方便实例化操作,提供了大量的缓存字段,方便重复实例化时减少工作量。它可以单独作为一个 BeanDefinition,也可以作为其他 BeanDefinition 的父类。

属性解析

//BeanDefinitionHolder存储有Bean的名称、别名、BeanDefinition
@Nullable
private BeanDefinitionHolder decoratedDefinition;
//是java反射包的接口,通过它可以查看Bean的注解信息
@Nullable
private AnnotatedElement qualifiedElement;
//允许缓存
boolean allowCaching = true;
//从字面上理解:工厂方法是否唯一
boolean isFactoryMethodUnique = false;
//封装了java.lang.reflect.Type,提供了泛型相关的操作
@Nullable
volatile ResolvableType targetType;
//缓存class,表明RootBeanDefinition存储哪个类的信息
@Nullable
volatile Class<?> resolvedTargetType;
//缓存工厂方法的返回类型
@Nullable
volatile ResolvableType factoryMethodReturnType;
//缓存工厂方法
@Nullable
volatile Method factoryMethodToIntrospect;
//以下四个变量的锁
final Object constructorArgumentLock = new Object();
//缓存已经解析的构造函数或是工厂方法,Executable是Method、Constructor类型的父类
@Nullable
Executable resolvedConstructorOrFactoryMethod;
//表明构造函数参数是否解析完毕
boolean constructorArgumentsResolved = false;
//缓存完全解析的构造函数参数
@Nullable
Object[] resolvedConstructorArguments;
//缓存待解析的构造函数参数,即还没有找到对应的实例,可以理解为还没有注入依赖的形参(我的理解)
@Nullable
Object[] preparedConstructorArguments;
//以下两个变量的锁
final Object postProcessingLock = new Object();
//表明是否被MergedBeanDefinitionPostProcessor处理过
boolean postProcessed = false;
//在生成代理的时候会使用,表明是否已经生成代理
@Nullable
volatile Boolean beforeInstantiationResolved;

以下三个属性是外部管理的方法集合(配置、初始化、銷毀),似乎可以缓存自动装配对象的值

// 实际缓存的类型是Constructor、Field、Method类型
@Nullable
private Set<Member> externallyManagedConfigMembers;
@Nullable
// InitializingBean中的init回调函数名——afterPropertiesSet会在这里记录,以便进行生命周期回调
private Set<String> externallyManagedInitMethods;

@Nullable
// DisposableBean的destroy回调函数名——destroy会在这里记录,以便进行生命周期回调
private Set<String> externallyManagedDestroyMethods;

补充

MergedBeanDefinition:这个词其实不是一个官方词,但是很接近,该词主要是用来表示 “合并的 bean 定义”,因为每次都写 “合并的 bean 定义” 有点太绕口,因此我在之后的注释或解析中或统一使用 MergedBeanDefinition 来表示 “合并的 bean 定义”。
之所以称之为 “合并的”,是因为存在 “子定义” 和 “父定义” 的情况。对于一个 bean 定义来说,可能存在以下几种情况:
该 BeanDefinition 存在 “父定义”:首先使用 “父定义” 的参数构建一个 RootBeanDefinition,然后再使用该 BeanDefinition 的参数来进行覆盖。
该 BeanDefinition 不存在 “父定义”,并且该 BeanDefinition 的类型是 RootBeanDefinition:直接返回该 RootBeanDefinition 的一个克隆。
该 BeanDefinition 不存在 “父定义”,但是该 BeanDefinition 的类型不是 RootBeanDefinition:使用该 BeanDefinition 的参数构建一个 RootBeanDefinition。
之所以区分出2和3,是因为通常 BeanDefinition 在之前加载到 BeanFactory 中的时候,通常是被封装成 GenericBeanDefinition 或 ScannedGenericBeanDefinition,但是从这边之后 bean 的后续流程处理都是针对 RootBeanDefinition,因此在这边会统一将 BeanDefinition 转换成 RootBeanDefinition。

AnnotatedGenericBeanDefinition

属性

  • AnnotationMetadata:主要对 Bean 的注解信息进行操作,如:获取当前 Bean 标注的所有注解、判断是否包含指定注解。
  • MethodMetadata:方法的元数据类。提供获取方法名称、此方法所属类的全类名、是否是抽象方法、判断是否是静态方法、判断是否是final方法等。

image-20230113170119845

解析

AnnotatedGenericBeanDefinition主要用于描述标注@Configuration注解的Bean。PS:需要明白注解方式载入BeanDefinition是通过工厂后置处理器ConfigurationClassPostProcessor实现的。

ConfigurationClassPostProcessor#processConfigBeanDefinitions(BeanDefinitionRegistry registry)
ConfigurationClassBeanDefinitionReader#loadBeanDefinitions(Set<ConfigurationClass> configurationModel)
	loadBeanDefinitionsForConfigurationClass(ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator)
	registerBeanDefinitionForImportedConfigurationClass(ConfigurationClass configClass)

image-20230113174211969

ScannedGenericBeanDefinition

该类继承自 GenericBeanDefinition,并实现了AnnotatedBeanDefinition接口。这个BeanDefinition用来描述标注@Component注解的 Bean,其派生注解如 @Service@Controller也同理.PS:需要明白注解方式载入BeanDefinition是通过工厂后置处理器ConfigurationClassPostProcessor实现的。

解析路径:

ConfigurationClassPostProcessor#processConfigBeanDefinitions(BeanDefinitionRegistry registry)
ConfigurationClassParser#parse(Set<BeanDefinitionHolder> configCandidates)
	parse(AnnotationMetadata metadata, String beanName)
	processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter)
	doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
ComponentScanAnnotationParser#parse(AnnotationAttributes componentScan, final String declaringClass)
ClassPathBeanDefinitionScanner#doScan(String... basePackages)
ClassPathScanningCandidateComponentProvider#findCandidateComponents(String basePackage)
	scanCandidateComponents(String basePackage)

image-20230113171344019

ConfigurationClassBeanDefinition

该类继承自 RootBeanDefinition ,并实现了 AnnotatedBeanDefinition 接口。这个BeanDefinition用来描述在标注 @Configuration 注解的类中,通过 @Bean 注解实例化的 Bean 。PS:需要明白注解方式载入BeanDefinition是通过工厂后置处理器ConfigurationClassPostProcessor实现的。

解析路径:

ConfigurationClassPostProcessor#processConfigBeanDefinitions(BeanDefinitionRegistry registry)
ConfigurationClassBeanDefinitionReader#loadBeanDefinitions(Set<ConfigurationClass> configurationModel)
	loadBeanDefinitionsForConfigurationClass(ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator)
	loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod)

image-20230113170717283

注解相关

懒加载

对某个bean进行延迟加载(延迟到在第一次调用的时候实例化)

@Lazy注解只对单例有用

解决Spring 循环依赖的一个简单方法就是对一个Bean使用延时加载

初始化

@PostConstruct,InitializingBean,以及SmartInitializingSingleton

@PostConstruct是最先被执行的,然后是InitializingBean,最后是SmartInitializingSingleton

构造方法 >@PostContruct > afterPropertiesSet()> init-method

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/169646.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

AioDnsBrute:一款功能强大的异步DNS爆破工具

关于AioDnsBrute AioDnsBrute是一款功能强大的异步DNS爆破工具&#xff0c;该工具基于Python 3.5开发&#xff0c;并使用了asyncio库以实现针对目标域名的异步爆破。 该工具的运行速度非常快&#xff0c;在一台小型VPS主机上&#xff0c;可以实现在1.5-2分钟之内处理大约10万…

【计数DP】P4933 大师

这道是洛谷官方题单的简单DP为啥我放上来呢&#xff0c;因为我因为各种各样的细节原因没做出来感觉计数的DP有点点难&#xff0c;得多写了P4933 大师 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)题意&#xff1a;思路&#xff1a;第一眼肯定是设dp[i][j]为以a[i]为结尾&…

8. 【Redisson源码】分布式信号量RSemaphore

目录 一、RSemaphore的使用 二、RSemaphore设置许可数量 三、RSemaphore的加锁流程 四、RSemaphore的解锁流程 【本篇文章基于redisson-3.17.6版本源码进行分析】 基于Redis的Redisson的分布式信号量RSemaphore采用了与java.util.concurrent.Semaphore相似的接口和用法。 …

从首个「数实融合」公益球场,看元宇宙奏响创新「三重奏」

作者 | 曾响铃 文 | 响铃说 2022年的元宇宙&#xff0c;一半是海水&#xff0c;一半是火焰。 一边是刮起元宇宙热潮的Roblox股价跌去大半&#xff0c;Meta也因元宇宙亏损深陷泥潭。另一边&#xff0c;经过2021年元宇宙概念落地和普及&#xff0c;2022年却也是元宇宙相关产业…

分享86个PHP源码,总有一款适合您

PHP源码 分享86个PHP源码&#xff0c;总有一款适合您 下面是文件的名字&#xff0c;我放了一些图片&#xff0c;文章里不是所有的图主要是放不下...&#xff0c; 86个PHP源码下载链接&#xff1a;https://pan.baidu.com/s/1fsoGdkr_-wZUaJvVMOlihQ?pwdlhyo 提取码&#xff…

Java 泛型是什么?一文带你吃透泛型

文章目录1. Java 泛型2. 泛型类3. 泛型接口4. 泛型方法5. 泛型集合Java编程基础教程系列1. Java 泛型 Java 泛型是 JDK1.5 中引入的一个新特性&#xff0c;其本质是参数化类型&#xff0c;把类型作为参数传递。其主要的形式有泛型类&#xff0c;泛型接口和泛型方法。泛型概念的…

sqoop安装(linux)

一、前期准备安装好hadoop伪分布安装好MySQL下载sqoop压缩文件实验环境&#xff1a;实验环境版本CentOS 6.5MySQL5.7.37hadoop3.3.0sqoop1.4.7sqoop1.4.7 下载链接&#xff1a;https://pan.baidu.com/s/16AUdtBmSv7OG2PTyA1XcgQ?pwdqu7lmysql驱动包下载地址&#xff1a;https:…

易于设置的倒计时页面Easy countdown

今天开始放假了 什么是 Easy countdown &#xff1f; Easy countdown 是一个易于设置的倒计时页面。可以设置为倒计时或计时器。 先看看官方提供的动图 安装 在群晖上以 Docker 方式安装。 在注册表中搜索 easy-countdown &#xff0c;选择第一个 yooooomi/easy-countdown&am…

【前端学习指南】基础开发环境搭建

&#x1f36d; Hello&#xff0c;我是爱吃糖的范同学 邻近春节&#xff0c;虽然学校的事情已经处理的差不多了&#xff0c;又开始要忙着找实习......时间安排上还是有很多问题&#xff0c;希望大家多多包涵&#xff0c;我已经加班加点在写作了&#x1f602;&#x1f602;&…

高盐废水如何处理,离子交换树脂在高盐废水中的应用

什么是高盐废水&#xff1f; 高盐废水是工业废水中较常见的一种&#xff0c;它是指总含盐量(以NaCl计&#xff09;至少为1%的废水&#xff0c;属于难处理的废水之一。 高盐废水中的总溶解固体物TDS&#xff0c;多在10000-25000mg/L&#xff0c;含盐成分复杂&#xff0c;有Na、…

vue3中echarts组件的最佳封装形式

项目中经常用到echarts&#xff0c;不做封装直接拿来使用也行&#xff0c;但不可避免要写很多重复的配置代码&#xff0c;封装稍不注意又会过度封装&#xff0c;丢失了扩展性和可读性。始终没有找到一个好的实践&#xff0c;偶然看到一篇文章&#xff0c;给了灵感。找到了一个目…

【数据结构】并查集

目录1.概述2.代码实现3.应用本文参考&#xff1a; LABULADONG 的算法网站 《数据结构教程》&#xff08;第 5 版&#xff09;李春葆主编 1.概述 &#xff08;1&#xff09;并查集支持查找一个元素所属的集合以及两个元素各自所属的集合的合并运算。当给出两个元素的一个无序对…

氨氮废水如何处理,离子交换树脂在氨氮废水中的应用点

近几年来重点污染源考核结果及地表水监测结果表明&#xff0c;氨氮超标现象仍较严重。认清氨氮的来源&#xff0c;了解其危害&#xff0c;采取有效的处理措施成为保护水环境不被氨氮污染的必要环节。 北京科海思科技有限公司利用离子交换特种树脂可以做到有针对性的氨氮的去除…

vue2之生命周期

生命周期 生命周期是指组件从创建&#xff0c;运行到销毁的阶段。而生命周期函数&#xff08;也叫生命周期钩子&#xff09;是vue在关键的时刻帮我们调用的一些特殊名称的函数&#xff0c;会根据生命周期的阶段&#xff0c;依次执行。 beforeCreatecreatedbeforeMountmountedb…

基本的SELECT语句与显示表结构

文章目录基本的SELECT语句SELECT...SELECT ... FROM列的别名去除重复行空值参与运算着重号查询常数(查询同时添加常数字段)显示表结构过滤数据练习题基本的SELECT语句 SELECT… SELECT 11, 22;# 直接这样写相当于下面这句 SELECT 11, 22 FROM DUAL; # 这里DUAL&#xff1a;伪…

【云攻防系列】从攻击者视角聊聊K8S集群安全(上)

前言 作为云原生管理与编排系统的代表&#xff0c;Kubernetes&#xff08;简称K8S&#xff09;正受到越来越多的关注&#xff0c;有报告[1]显示&#xff0c;96% 的组织正在使用或评估 K8S&#xff0c;其在生产环境下的市场占有率可见一斑。 K8S 的功能十分强大&#xff0c;其…

day38【代码随想录】动态规划之斐波那契数、爬楼梯、使用最小花费爬楼梯

文章目录前言一、斐波那契数&#xff08;力扣509&#xff09;二、爬楼梯&#xff08;力扣70&#xff09;三、使用最小花费爬楼梯&#xff08;力扣746&#xff09;总结前言 1、斐波那契数 2、爬楼梯 3、使用最小花费爬楼梯 一、斐波那契数&#xff08;力扣509&#xff09; 思路…

详解C语言预处理

个人主页&#xff1a;平行线也会相交 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 平行线也会相交 原创 收录于专栏【C/C】 本文目录程序的翻译环境和执行环境翻译环境&#xff08;C语言程序的编译链接&#xff09;执行&#xff08;运行&#xff09;环境…

扩展Linux根目录磁盘空间

问题&#xff1a;如果一开始创建虚拟机&#xff0c;挂载给虚拟机根目录&#xff08;/&#xff09;的磁盘空间太小了&#xff0c;所以磁盘空间很快就会填满。如果根目录的磁盘空间占用超过90%&#xff0c;会导致无法再新安装软件。 查看根目录磁盘空间&#xff1a; 可以--右键…

导入若依项目数据库脚本到mysql数据库

使用DBeaver工具连接本地mysql数据库 在之前的文章中&#xff0c;已经介绍过&#xff0c;怎么样去寻找某款软件的替代软件了&#xff0c;如果不知道怎么找的&#xff0c;可以再看看之前的文章&#xff1a;为大家介绍一个我常用的搜索同类替代软件的网站 大家都知道&#xff0c;…