【spring源码分析】@Conditional的使用以及分析

@Conditional

  • @Conditional
    • 一、基本信息
    • 二、注解描述
    • 三、注解源码
    • 四、主要功能
    • 五、最佳实践
      • 在@Bean上使用
      • 在@Configuration上使用
      • 自定义组合注解
    • 六、时序图
    • 七、源码分析
    • 八、注意事项
    • 九、总结
      • 最佳实践总结
      • 源码分析总结

一、基本信息

转载自github,在此作为个人备份(https://blog.csdn.net/duzhuang2399/article/details/133800722)
📚 文章目录 - 所有文章
🔗 源码地址 - @Conditional源码

二、注解描述

@Conditional注解,是用来基于满足某些特定条件来决定一个Bean是否应该被注册到Spring容器的。这提供了一种灵活的方式来根据环境、配置或其他因素来决定是否激活或者创建某个Bean。

三、注解源码

@Conditional注解是 Spring 框架自 3.0 版本开始引入的一个核心注解,用于指示一个组件只在所有指定条件匹配时才能被注册。

/*** 表明只有当所有指定的条件都满足时,组件才有资格被注册。** 条件是可以在bean定义被注册前以编程方式确定的任何状态(参考 Condition 获取详情)。** @Conditional 注解可以以下列方式使用:* * 作为直接或间接使用 @Component 注解的任何类的类型级别注解,包括 Configuration @Configuration 类* 作为元注解,用于组合自定义的范型注解* 作为任何 Bean @Bean 方法的方法级别注解* ** 如果一个 @Configuration 类标记为 @Conditional,与该类关联的所有 @Bean 方法、Import @Import 注解,* 和 ComponentScan @ComponentScan 注解都将受到这些条件的限制。** 注意:不支持 @Conditional 注解的继承;任何从超类或从被覆盖的方法继承的条件都不会被考虑。* 为了强制这些语义,@Conditional 本身未声明为 java.lang.annotation.Inherited @Inherited;* 此外,任何用  @Conditional 作为元注解的自定义组成注解也不应声明为 @Inherited。** @author Phillip Webb* @author Sam Brannen* @since 4.0* @see Condition*/
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {/*** 所有必须满足的 {@link Condition} 类,以便组件可以被注册。*/Class<? extends Condition>[] value();
}

四、主要功能

  1. 条件化 Bean 注册
    • 可以根据特定的条件来决定是否创建并注册一个 Bean。这允许我们根据环境、配置或其他因素动态地选择哪些 Bean 需要被实例化。
  2. 条件化配置类
    • 不仅可以对单个 Bean 使用,还可以对整个配置类使用。如果配置类上的条件不满足,那么该配置类中定义的所有 Beans 都不会被注册。
  3. 灵活性
    • 与一个实现了 Condition 接口的类一起使用。这个接口允许我们定义自己的条件逻辑,使得其可以非常灵活地根据各种场景来决定是否注册 Bean。
  4. 与其他注解组合
    • 除了与 @Bean@Configuration 注解一起使用外,@Conditional 还可以作为元注解,用于创建自定义的组合注解,这些组合注解内部使用 @Conditional 来应用条件逻辑。
  5. 对整个配置类的影响
    • @Conditional 用于配置类时,不仅仅是该类,还有与该类关联的所有 @Bean 方法、@Import 注解和 @ComponentScan 注解都将受到条件的影响。
  6. 不支持继承
    • @Conditional 注解本身不是继承的,因此,从父类或接口继承的条件不会被子类考虑。

五、最佳实践

在@Bean上使用

首先来看看启动类入口,首先设置一个系统属性enable.beantrue,然后上下文环境使用AnnotationConfigApplicationContext(此类是使用Java注解来配置Spring容器的方式),构造参数我们给定了一个MyConfiguration组件类,最后打印了Spring上下文中所有的bean定义名称。

public class ConditionBeanApplication {public static void main(String[] args) {System.setProperty("enable.bean","true");AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyBeanConfiguration.class);for (String beanDefinitionName : context.getBeanDefinitionNames()) {System.out.println("beanDefinitionName = " + beanDefinitionName);}}
}

MyBeanConfiguration,其中定义了两个bean:user1user2user1 bean的创建是基于条件的,具体取决于BeanPropertyCondition条件的结果。而user2 bean则无条件创建。

@Configuration
public class MyBeanConfiguration {@Bean@Conditional(BeanPropertyCondition.class)public User1 user1() {return new User1();}@Beanpublic User2 user2() {return new User2();}
}

BeanPropertyCondition。这个实现会根据enable.bean属性的值决定是否满足条件。具体来说:如果环境属性enable.bean的值是true,则user1 bean会被创建并添加到Spring容器。如果enable.bean不是true(或者没有设置这个属性),user1 bean不会被创建。

public class BeanPropertyCondition implements Condition {@Overridepublic boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {return "true".equals(context.getEnvironment().getProperty("enable.bean"));}
}

定义两个简单的Java类:User1User2

public class User1 {}public class User2 {}

enable.beantrue运行结果发现,根据enable.bean属性的值来注册user1 bean,而user2 bean则不受此属性的影响。

beanDefinitionName = myBeanConfiguration
beanDefinitionName = user1
beanDefinitionName = user2

enable.beanfalse运行结果发现,enable.bean值为false,所以条件不满足。因此user1bean不会被注册,user2 bean不受任何条件的影响。

beanDefinitionName = myBeanConfiguration
beanDefinitionName = user2
在@Configuration上使用

首先来看看启动类入口,首先设置一个系统属性enable.configtrue,然后上下文环境使用AnnotationConfigApplicationContext(此类是使用Java注解来配置Spring容器的方式),构造参数我们给定了一个MyConfiguration组件类,最后打印了Spring上下文中所有的bean定义名称。

public class ConditionConfigurationApplication {public static void main(String[] args) {System.setProperty("enable.config","true");AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfigConfiguration.class);for (String beanDefinitionName : context.getBeanDefinitionNames()) {System.out.println("beanDefinitionName = " + beanDefinitionName);}}
}

MyConfigConfiguration,其中定义了两个bean:user3user4。当ConfigPropertyCondition条件不满足时MyConfigConfiguration配置类不被激活,该配置类中定义的user3user4不会被注册。

@Configuration
@Conditional(ConfigPropertyCondition.class)
public class MyConfigConfiguration {@Beanpublic User3 user3() {return new User3();}@Beanpublic User4 user4() {return new User4();}
}

ConfigPropertyCondition。这个实现会根据enable.config属性的值决定是否满足条件。具体来说:当enable.config设置为trueConfigPropertyCondition满足,MyConfigConfiguration配置类被激活,user3user4 beans都将被注册到Spring上下文。当enable.config设置为false或未设置,ConfigPropertyCondition不满足,MyConfigConfiguration配置类不被激活,user3user4 beans都不会被注册。

public class ConfigPropertyCondition implements Condition {@Overridepublic boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {return "true".equals(System.getProperty("enable.config"));}
}

定义两个简单的Java类:User3User4

public class User3 {}public class User4 {}

enable.configtrue运行结果发现,MyConfigConfiguration中的user3user4都被注册了。

beanDefinitionName = myConfigConfiguration
beanDefinitionName = user3
beanDefinitionName = user4

enable.configfalse运行结果发现,我们不会看到任何与 MyConfigConfiguration (包括它自己)相关的 beans 被注册了。

无任何bean
自定义组合注解

首先来看看启动类入口,首先设置一个系统属性enable.customtrue,然后上下文环境使用AnnotationConfigApplicationContext(此类是使用Java注解来配置Spring容器的方式),构造参数我们给定了一个MyConfiguration组件类,最后打印了Spring上下文中所有的bean定义名称。

public class ConditionCustomApplication {public static void main(String[] args) {System.setProperty("enable.custom","true");AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyCustomConfiguration.class);for (String beanDefinitionName : context.getBeanDefinitionNames()) {System.out.println("beanDefinitionName = " + beanDefinitionName);}}
}

MyCustomConfiguration,其中定义了两个bean:user5user6。如果@ConditionalOnCustomActive的条件满足,MyCustomConfiguration配置类将被激活,在此配置类中定义user5user6将被注册到Spring容器中。如果@ConditionalOnCustomActive的条件不满足,MyCustomConfiguration配置类将不被激活。user5user6 beans都不会被注册。

@Configuration
@ConditionalOnCustomActive
public class MyCustomConfiguration {@Beanpublic User5 user5() {return new User5();}@Beanpublic User6 user6() {return new User6();}
}

@ConditionalOnCustomActive定义了一个组合注解,并通过@Conditional元注解将其关联到CustomActiveCondition

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Conditional(CustomActiveCondition.class)
public @interface ConditionalOnCustomActive {}

CustomActiveCondition。这个实现会根据enable.custom属性的值决定是否满足条件。具体来说:当enable.custom设置为trueCustomActiveCondition满足条件,因为matches方法会返回trueMyCustomConfiguration配置类由于带有@ConditionalOnCustomActive注解(该注解内部引用了CustomActiveCondition)将被激活,在该配置类中定义的user5user6将被注册到Spring容器中。当enable.custom设置为false或未设置CustomActiveCondition不满足条件,因为matches方法会返回false,由于MyCustomConfiguration带有@ConditionalOnCustomActive注解,该配置类不被激活。user5user6 beans都不会被注册。

public class CustomActiveCondition implements Condition {@Overridepublic boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {return "true".equals(System.getProperty("enable.custom"));}
}

定义两个简单的Java类:User5User6

public class User5 {}public class User6 {}

enable.customtrue运行结果发现,我们的组合注解 @ConditionalOnCustomActive 和相应的条件 CustomActiveCondition 正常工作,正确地根据 enable.custom 系统属性的值来激活 MyCustomConfiguration 配置类。

beanDefinitionName = myCustomConfiguration
beanDefinitionName = user5
beanDefinitionName = user6

enable.customfalse运行结果发现,与 MyCustomConfiguration 相关的任何 beans(包括它自己)都不会被注册到 Spring 容器中。

无任何bean

六、时序图

ConditionCustomApplication AnnotationConfigApplicationContext ConfigurationApplication AnnotatedBeanDefinitionReader ConditionEvaluator AnnotationAwareOrderComparator CustomActiveCondition AnnotationConfigApplicationContext(componentClasses) 启动上下文 返回context 返回上下文实例 register(componentClasses) 注册组件类 register(componentClasses) 读取器注册类 registerBean(beanClass) 注册Bean类 doRegisterBean(beanClass,name,qualifiers, supplier,customizers) 执行Bean注册 shouldSkip(metadata) shouldSkip(metadata,phase) getConditionClasses(metadata) 返回 List<String[]> getCondition(conditionClassName,classloader) sort(conditions) matches(context,metadata) 返回true or false 返回true or false 如果shouldSkip返回是true,跳过Bean的注册 ConditionCustomApplication AnnotationConfigApplicationContext ConfigurationApplication AnnotatedBeanDefinitionReader ConditionEvaluator AnnotationAwareOrderComparator CustomActiveCondition

七、源码分析

首先来看看启动类入口,首先设置一个系统属性enable.customtrue,然后上下文环境使用AnnotationConfigApplicationContext(此类是使用Java注解来配置Spring容器的方式),构造参数我们给定了一个MyConfiguration组件类,最后打印了Spring上下文中所有的bean定义名称。

public class ConditionCustomApplication {public static void main(String[] args) {System.setProperty("enable.custom","true");AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyCustomConfiguration.class);for (String beanDefinitionName : context.getBeanDefinitionNames()) {System.out.println("beanDefinitionName = " + beanDefinitionName);}}
}

org.springframework.context.annotation.AnnotationConfigApplicationContext#AnnotationConfigApplicationContext构造函数中,执行了三个步骤,我们重点关注refresh()方法。

public AnnotationConfigApplicationContext(Class<?>... componentClasses) {this();register(componentClasses);refresh();
}

org.springframework.context.annotation.AnnotationConfigApplicationContext#register方法中,主要是允许我们注册一个或多个组件类(例如,那些使用 @Component, @Service, @Repository, @Controller, @Configuration 等注解的类)到Spring容器。

@Override
public void register(Class<?>... componentClasses) {Assert.notEmpty(componentClasses, "At least one component class must be specified");StartupStep registerComponentClass = this.getApplicationStartup().start("spring.context.component-classes.register").tag("classes", () -> Arrays.toString(componentClasses));this.reader.register(componentClasses);registerComponentClass.end();
}

org.springframework.context.annotation.AnnotatedBeanDefinitionReader#register方法中,遍历每一个传入的组件类,并逐一调用另一个方法来完成实际的注册工作。

public void register(Class<?>... componentClasses) {for (Class<?> componentClass : componentClasses) {registerBean(componentClass);}
}

org.springframework.context.annotation.AnnotatedBeanDefinitionReader#registerBean(beanClass)方法中,主要目的是快速注册一个 bean 类型,而不需要指定其他详细的配置或参数。

public void registerBean(Class<?> beanClass) {doRegisterBean(beanClass, null, null, null, null);
}

org.springframework.context.annotation.AnnotatedBeanDefinitionReader#doRegisterBean方法中,主要用于条件性注册 bean 的逻辑,只有当特定的条件满足时,bean 才会被注册。

private <T> void doRegisterBean(Class<T> beanClass, @Nullable String name,@Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier,@Nullable BeanDefinitionCustomizer[] customizers) {// 基于给定的 bean 类创建一个带注解的 bean 定义。AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);// 利用条件评估器检查是否应该跳过当前 bean 的注册。// 如果 bean 不满足指定的条件,那么将直接返回,不继续执行后续的注册逻辑。if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {return;}// ... [代码部分省略以简化]
}

org.springframework.context.annotation.ConditionEvaluator#shouldSkip(metadata)方法中,又委托给另一个版本的 shouldSkip 方法,并为第二个参数传入 null

public boolean shouldSkip(AnnotatedTypeMetadata metadata) {return shouldSkip(metadata, null);
}

org.springframework.context.annotation.ConditionEvaluator#shouldSkip(metadata,phase)方法中,主要目的是决定是否应根据给定的条件(通常由 @Conditional 注解定义)跳过某个配置类或 bean 的注册。

/*** 根据提供的元数据和配置阶段判断是否应跳过某个操作或逻辑。** @param metadata 元数据,与注解相关。* @param phase    当前的配置阶段,可能为 null。* @return 如果应跳过,则返回 true;否则返回 false。*/
public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata, @Nullable ConfigurationPhase phase) {// 如果元数据为空或未标注 @Conditional 注解,则不跳过。if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) {return false;}// 如果没有指定配置阶段,确定正确的配置阶段。if (phase == null) {// 如果元数据是注解元数据,并且是配置候选项,则选择 PARSE_CONFIGURATION 阶段。if (metadata instanceof AnnotationMetadata &&ConfigurationClassUtils.isConfigurationCandidate((AnnotationMetadata) metadata)) {return shouldSkip(metadata, ConfigurationPhase.PARSE_CONFIGURATION);}// 否则选择 REGISTER_BEAN 阶段。return shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN);}// 获取所有的条件,并从相关的条件类实例化它们。List<Condition> conditions = new ArrayList<>();for (String[] conditionClasses : getConditionClasses(metadata)) {for (String conditionClass : conditionClasses) {Condition condition = getCondition(conditionClass, this.context.getClassLoader());conditions.add(condition);}}// 对条件进行排序。AnnotationAwareOrderComparator.sort(conditions);// 遍历所有条件,检查它们是否与当前配置阶段匹配。for (Condition condition : conditions) {ConfigurationPhase requiredPhase = null;if (condition instanceof ConfigurationCondition) {requiredPhase = ((ConfigurationCondition) condition).getConfigurationPhase();}// 如果条件不匹配上下文和元数据,则跳过。if ((requiredPhase == null || requiredPhase == phase) && !condition.matches(this.context, metadata)) {return true;}}return false;
}

org.springframework.context.annotation.ConditionEvaluator#getConditionClasses方法中,从提供的注解元数据中获取与 @Conditional 注解关联的条件类的名称。

/*** 从提供的注解元数据中获取与 @Conditional 注解关联的条件类的名称。** @param metadata 元数据,通常与某个 bean 或配置类的注解相关。* @return 一个列表,其中包含与 @Conditional 注解关联的条件类的名称。如果没有相关的条件类,则返回一个空列表。*/
private List<String[]> getConditionClasses(AnnotatedTypeMetadata metadata) {// 获取 @Conditional 注解的所有属性值。MultiValueMap<String, Object> attributes = metadata.getAllAnnotationAttributes(Conditional.class.getName(), true);// 试图从属性值中获取 "value",它应该是一个指向条件类名称的引用。Object values = (attributes != null ? attributes.get("value") : null);// 返回条件类名称的列表,或者如果没有条件类,则返回一个空列表。return (List<String[]>) (values != null ? values : Collections.emptyList());
}

org.springframework.context.annotation.ConditionEvaluator#getCondition方法中,根据给定的条件类名称和类加载器实例化一个 Condition 对象。

/*** 根据提供的条件类名称和类加载器实例化一个 Condition 对象。** @param conditionClassName 条件类的完全限定名。* @param classloader 用于加载条件类的类加载器,可以为 null。* @return 实例化的 Condition 对象。*/
private Condition getCondition(String conditionClassName, @Nullable ClassLoader classloader) {// 使用类加载器解析并加载指定的条件类。Class<?> conditionClass = ClassUtils.resolveClassName(conditionClassName, classloader);// 实例化解析的条件类并返回。return (Condition) BeanUtils.instantiateClass(conditionClass);
}

八、注意事项

  1. 实现 Condition 接口
    • 为了使用 @Conditional, 我们需要实现 Condition 接口。该接口只有一个方法,matches(ConditionContext context, AnnotatedTypeMetadata metadata),我们需要在这里放置我们的条件逻辑。
  2. 类级别和方法级别
    • @Conditional 可以应用于 @Bean 方法,用于控制特定 bean 的创建。
    • 也可以应用于 @Configuration 类,控制整个配置类的加载。
  3. 组合多个条件
    • 可以使用 @Conditional 注解的数组形式来组合多个条件,所有条件都必须满足才能创建 bean。
  4. 与其他注解的组合
    • @Conditional 可以与其他注解一起使用,如 @Profile。但是注意他们之间的交互效果。例如,如果一个 bean 标记为特定的 @Profile 并且使用 @Conditional,那么两者都必须为 true 才能创建该 bean。
  5. 避免复杂的逻辑
    • 虽然 Condition 允许我们编写任意的条件逻辑,但最好避免过于复杂。简单明了的逻辑更易于理解和维护。
  6. 性能
    • matches 方法可能会在应用的生命周期中被多次调用,因此应确保其执行效率,避免在此方法中进行高开销的操作。
  7. 配合 ConditionContext:
    • ConditionContext 提供了关于当前应用上下文、环境属性、系统属性等的信息,可以使我们的条件判断更加具体和强大。
  8. 自定义条件注解
    • 为了重用或组合多个条件,我们可以创建自己的条件注解。例如,我们可以创建一个 @ConditionalOnCustomActive 注解,它封装了检查enable.custom的条件。
  9. 注意与 @Profile 的区别
    • 虽然 @Conditional@Profile 在某些情况下可以达到相同的效果,但它们的目的不同。@Profile 基于环境,而 @Conditional 更加通用,允许我们基于任意条件创建 bean。

九、总结

最佳实践总结
  1. 基于@Bean的条件配置

    • 场景描述
  • 在单个bean的创建上应用条件。
  • 实现方法
  • 通过在@Bean注解方法上直接使用@Conditional
  • 结果
    • 当条件满足(如enable.beantrue),特定的bean(如user1)会被注册。
    • 当条件不满足,该bean不会被注册。
  1. 基于@Configuration的条件配置

    • 场景描述
  • 控制整个配置类的激活状态,从而影响该配置中定义的所有beans。
  • 实现方法
  • @Configuration注解的类上直接使用@Conditional
  • 结果
    • 当条件满足(如enable.configtrue),配置类被激活,其内部的所有beans(如user3user4)都会被注册。
    • 当条件不满足,配置类及其内部定义的所有beans都不会被注册。
  1. 使用自定义组合注解

    • 场景描述
      • 创建自己的条件注解,以提供更清晰、更简洁的语法,或为特定的业务逻辑封装条件逻辑。
    • 实现方法
      • 定义一个新的注解(如@ConditionalOnCustomActive),并使用@Conditional元注解将其关联到特定的条件类。
    • 结果
      • 当条件满足(如enable.customtrue),带有@ConditionalOnCustomActive注解的配置类或bean会被注册。
      • 当条件不满足,它们不会被注册。
源码分析总结
  1. 初始化与启动

    • 通过 AnnotationConfigApplicationContext 构造函数初始化 Spring 上下文,并通过 registerrefresh 方法完成 bean 的注册和容器的刷新。
  2. 注册组件类

    • 使用 AnnotatedBeanDefinitionReader 来注册组件类。在 register 方法中,每一个组件类都会通过 registerBean 方法进行注册。
  3. 条件检查

    • doRegisterBean 方法中,执行了核心的条件检查逻辑。使用 ConditionEvaluator 来评估与给定 bean 或配置类关联的条件是否满足。
  4. 元数据检查

    • ConditionEvaluator 会首先检查提供的元数据(通常与特定的 bean 或配置类的注解关联)是否包含 @Conditional 注解。如果没有,直接进行下一步。如果存在,继续检查条件是否满足。
  5. 条件匹配

    • ConditionEvaluator 获取与 @Conditional 注解关联的所有条件类,并为每一个条件类创建一个实例。随后,它会遍历所有的条件,并检查它们是否满足。这是通过调用每一个条件的 matches 方法来完成的。如果任何一个条件不满足,整个条件检查逻辑返回 false,表示不应注册与 @Conditional 注解关联的 bean 或配置类。
  6. 条件实例化

    • 通过 getCondition 方法,ConditionEvaluator 能够根据提供的条件类名称和类加载器实例化一个 Condition 对象。

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

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

相关文章

LINUX基础培训六之磁盘和文件系统管理

前言、本章学习目标 掌握fdisk分区类型和管理分区了解parted分区类型掌握LVM模式文件系统创建、扩展、缩小文件系统 一、磁盘的分区管理 在 Linux 中有专门的分区命令 fdisk 和 parted。其中 fdisk 命令较为常用&#xff0c;但不支持大于 2TB 的分区&#xff1b;如果需要支…

C++/WinRT 入门

本主题将会根据新的 Windows 控制台应用程序 (C/WinRT) 项目演练一个简单的代码示例。 C/WinRT 快速入门 创建一个新的 Windows 控制台应用程序(C/WinRT) 项目。 根据实际选择平台 如果出现如下错误&#xff0c;需要安装正确的SDK。 找不到 Windows SDK 版本 10.0.17134.0 (o…

支付功能测试用例测试点?

支付功能测试用例测试点是指在测试支付功能时&#xff0c;需要关注和验证的各个方面。根据不同的支付场景和需求&#xff0c;支付功能测试用例测试点可能有所不同&#xff0c;但一般可以分为以下几类&#xff1a; 功能测试&#xff1a;主要检查支付功能是否符合设计和业务需求…

RTTI结构详细分析(VC++)

对于RTTI结构的资料真的屈指可数,类的逆向也一直是一个不好弄的问题.对此我只想贡献我的一份力量。 文中我不会分析类的内存布局,因为有很多资料已经分析的挺好的了(见参考资料)。但是现有我能找到的资料对RTTI结构的表述不完整,或者表述模糊不清,参考Clang的部分源码后&#…

kube-apiserver参数详解

Global flags 全局选项详解 选项默认值描述–log-file如果不为空,将是日志输出的文件–log-dir如果不为空,将是日志输出的目录–alsologtostderrlog日志会输出到标准错误并且也会输出到文件中–logtostderrtruelog日志会输出到标准错误而不是文件中–log-file-max-size1800定…

寒假刷题第五天

PTA甲级 1022 Digital Library 大模拟 #include<iostream> #include<unordered_map> #include<unordered_set> #include<vector> #include<set>using namespace std;unordered_map<string , set<int>>ti , au , key , pub , year…

Altium designer软件使用

AD工程文件 .prjpcb 工程由sch文件与pcb文件组成&#xff0c;sch文件是原理图文件&#xff0c;pcb文件是layout文件。 原理图SCH .schdoc 1&#xff1a;原理图的标注:加标题和作者 p->t tab 2&#xff1a;查找:ctrlF 3&#xff1a;设置相关功能的快捷键 View菜单下的Tool…

一些前端学习过程的自测练习题

目录 页面设计部分 1 设计一个简单的学院网站首页&#xff1b; 2.按照图示要求完成简单的登录页面 3.完成如下网站设计 4.完成如下网站设计&#xff08;练习页面布局&#xff09; 5 利用下面素材&#xff0c;设计一个满足H5规范的网页&#xff08;移动端页面练习&#xff…

【Delphi 基础知识 17】注释代码的几种方法

在 Delphi 中&#xff0c;有三种主要的注释代码的方法&#xff0c;分别是&#xff1a; 花括号 {} 注释&#xff1a; 这是一种常见的注释方式&#xff0c;在代码中使用花括号将注释的内容括起来。这种注释方式可以用于单行注释和多行注释。// 单行注释 { 这是一个多行注释可以跨…

简单说一下原型与原型链

文章目录 原型原型链 原型 简单来说原型就像是对象的 “爸爸”&#xff0c;每个对象都有一个原型。当你创建一个对象时&#xff0c;这个对象就会有一个内部链接&#xff0c;指向它的原型。你可以把原型想象成对象的一种模板&#xff0c;对象可以从中继承属性和方法。 举个例子…

Java中单体应用锁的局限性分布式锁

互联网系统架构的演进 在互联网系统发展之初&#xff0c;系统比较简单&#xff0c;消耗资源小&#xff0c;用户访问量也比较少&#xff0c;我们只部署一个Tomcat应用就可以满足需求。系统架构图如下: 一个Tomcat可以看作是一个JVM进程&#xff0c;当大量的请求并发到达系统时&…

(每日持续更新)jdk api之FileDescriptor基础、应用、实战

博主18年的互联网软件开发经验&#xff0c;从一名程序员小白逐步成为了一名架构师&#xff0c;我想通过平台将经验分享给大家&#xff0c;因此博主每天会在各个大牛网站点赞量超高的博客等寻找该技术栈的资料结合自己的经验&#xff0c;晚上进行用心精简、整理、总结、定稿&…

ios 推流 拉流

文章目录 1.协议2.流程3.框架 HaishinKit.swift 1.协议 iOS 直播专题5-推流 简书 2.流程 iOS-直播推拉流 简书 3.框架 HaishinKit.swift HaishinKit.swift - github

Redis:原理速成+项目实战——Redis企业级项目实战终结篇(HyperLogLog实现UV统计)

&#x1f468;‍&#x1f393;作者简介&#xff1a;一位大四、研0学生&#xff0c;正在努力准备大四暑假的实习 &#x1f30c;上期文章&#xff1a;Redis&#xff1a;原理速成项目实战——Redis实战14&#xff08;BitMap实现用户签到功能&#xff09; &#x1f4da;订阅专栏&am…

[易语言]使用易语言部署工业级人脸检测模型

【框架地址】 https://github.com/ShiqiYu/libfacedetection 【算法介绍】 Libfacedetection是一个开源的计算机视觉库&#xff0c;主要用于实时的人脸检测。它利用深度学习技术&#xff0c;特别是卷积神经网络&#xff08;CNN&#xff09;&#xff0c;实现了高精度的脸部定位…

了解JavaScript 加密、混淆和生成签名

分析并理解网站的 JavaScript 加密、混淆和生成签名的方法是 JavaScript 逆向工程中的一个重要方面。这些技术通常用于保护代码免遭未授权的访问和修改&#xff0c;或确保数据在传输过程中的安全性。 加密 目的&#xff1a;加密用于保护敏感数据&#xff0c;使得只有拥有正确密…

【java八股文】之MYSQL基础篇

1、数据库三大范式是什么 第一范式&#xff1a;每个列都不可以再拆分。 第二范式&#xff1a;在第一范式的基础上&#xff0c;非主键列完全依赖于主键&#xff0c;而不能是依赖于主键的一部分。 第三范式&#xff1a;在第二范式的基础上&#xff0c;非主键列只依赖于主键&#…

AtCoder ABC194

这期比193稍微简单一点 C - Squared Error 手玩一下&#xff1a; N 3 N3 N3时 展开得 a 2 b 2 − 2 a b b 2 − c 2 − 2 b c a 2 c 2 − 2 a c a^2b^2-2abb^2-c^2-2bca^2c^2-2ac a2b2−2abb2−c2−2bca2c2−2ac 每个数平方项都要计算 n − 1 n-1 n−1次 减的那一份可…

LeetCode1124. Longest Well-Performing Interval

文章目录 一、题目二、题解 一、题目 We are given hours, a list of the number of hours worked per day for a given employee. A day is considered to be a tiring day if and only if the number of hours worked is (strictly) greater than 8. A well-performing in…

C语言--结构体详解

C语言--结构体详解 1.结构体产生原因2.结构体声明2.1 结构体的声明2.2 结构体的初始化2.3结构体自引用 3.结构体内存对齐3.1 对齐规则3.2 为什么存在内存对齐3.3 修改默认对⻬数 4. 结构体传参 1.结构体产生原因 C语言将数据类型分为了两种&#xff0c;一种是内置类型&#xf…