spring注解方式整合Dubbo源码解析

news2024/11/15 4:50:22

系列文章目录


前言

本节我们的Dubbo源码版本基于2.6.x

在前一章我们的整合案例中,我们有几个比较关键的步骤:

  1. 在启动类上标注了@EnableDubbo注解
  2. 在provider类上面标注了@Service注解来提供dubbo服务
  3. 在消费的时候通过@Reference注解引入dubbo服务
  4. 在配置文件中配置应用名,协议,暴露端口,注册中心地址等。
  5. 在配置文件中配置应用名,协议,暴露端口,注册中心地址等。

一、EnableDubbo注解

  1. 这里可以看到EnableDubbo是一个复合注解,集成了@EnableDubboConfig@DubboComponentScan注解
    2. EnableDubbo注解的属性,其中scanBasePackagesscanBasePackageClasses默认都是空,这里是可以指定包扫描的路径或者基类的,然后multipleConfig默认是true

在这里插入图片描述

1.1、EnableDubboConfig注解

  1. 这里使用import注解导入了DubboConfigConfigurationRegistrar
  2. 这里EnableDubboConfig注解中的multiple属性默认为true

在这里插入图片描述

1.1.1、DubboConfigConfigurationRegistrar

  1. 首先获取EnableDubboConfig注解中的属性列表
  2. 这里会根据注解中的multiple属性判断是否是单一绑定配置还是多个实例绑定配置,这里multiple默认为true

在这里插入图片描述

这里单一实例和多实例的区别,如下所示,多实例就是协议我可能支持多种,这样会根据我们是否支持多实例来给每个协议都生成一个配置.

在这里插入图片描述

1.1.2、AnnotatedBeanDefinitionRegistryUtils#registerBeans

  1. 上面会根据单实例还是多实例的区别来判断传入的注解类是DubboConfigConfiguration.Single还是 DubboConfigConfiguration.Multiple.class,最终都会调用到registerBeans方法。
  2. 这里会构造一个AnnotatedBeanDefinitionReader类,然后会扫描上面传入的注解类,然后注入到spring容器中。

在这里插入图片描述

1.1.3、DubboConfigConfiguration

  1. 我们上面把Single or Multiple 注解到spring容器中,然后发现对应类上面也标注了@EnableDubboConfigBindings注解,二者的区别就是Multiple多了一个注解属性,multipletrue
  2. @EnableDubboConfigBindings注解中是一个@EnableDubboConfigBinding注解的数组,他的作用就是把配置文件中的配置信息和具体的类进行绑定。

在这里插入图片描述

1.1.4、EnableDubboConfigBindings注解

  1. 这里我们发现他也是通过import导入了一个DubboConfigBindingsRegistrar类。

在这里插入图片描述

1.1.5、DubboConfigBindingsRegistrar#registerBeanDefinitions

  1. 上面通过import导入了DubboConfigBindingsRegistrar,他是实现ImportBeanDefinitionRegistrar,spring就会在其生命周期中回调对应的registerBeanDefinitions`方法。
  2. 这里首先会获取EnableDubboConfigBindings注解中的属性列表
  3. 然后获取value属性,这里对应就是EnableDubboConfigBinding[]注解列表
  4. 然后创建了一个DubboConfigBindingRegistrar注册器
  5. spring的环境也就是ConfigurableEnvironment设置到注册器中,从environment中可以获取到配置文件中的配置信息
  6. 遍历EnableDubboConfigBinding[]注解列表,注册对应的BeanDefinition

在这里插入图片描述

1.1.6、DubboConfigBindingRegistrar#registerBeanDefinitions

例:@EnableDubboConfigBinding(prefix = “dubbo.applications”, type = ApplicationConfig.class, multiple = true),

  1. 这里首先会从EnableDubboConfigBinding中解析出来prefix属性的value,得到dubbo.applications
  2. 解析出来type属性,得到ApplicationConfig.class
  3. 解析出来multiple属性,得到true
  4. 把解析出来的参数全部传入调用registerDubboConfigBeans注册Dubbo的配置Bean

在这里插入图片描述

1.1.7、DubboConfigBindingRegistrar#registerDubboConfigBeans

  1. 这里调用getSubProperties方法从environment中,也就是我们配置文件中的配置里面解析出来指定前缀的配置
  2. 如果没有指定前缀的配置则不需要注册BeanDefinition
  3. 根据multiple属性,这里一般为true,这样我们如果配置了多种协议,那么就会生成多个beanName
  4. 给每个beanName都注册一个空的BeanDefinition,然后给每个Bean都注册一个DubboCOnfigBindingBeanPostProcessorbean的后置处理器
  5. 最后调用registerDubboConfigBeanCustomizers注册了一个NamePropertyDefaultValueDubboConfigBeanCustomizerbean

在这里插入图片描述

1.1.7.1、PropertySourcesUtils#getSubProperties

  1. propertySources转成MutablePropertySources
  2. 调用重载方法getSubProperties

在这里插入图片描述

  1. 这里就是遍历PropertySource,解析出来指定前缀的配置,然后缓存起来返回。

在这里插入图片描述

1.1.7.2、DubboConfigBindingRegistrar#resolveMultipleBeanNames

  1. 这里就是从配置中解析出来beanName。
    比如配置是如下:
    dubbo.protocols.p1.name=dubbo
    dubbo.protocols.p1.port=20880
    dubbo.protocols.p1.host=0.0.0.0
    这里properties传进来的就是
    p1.name=dubbo
    p1.port=20880

    那么解析出来的beanName就是p1

在这里插入图片描述

1.1.7.3、DubboConfigBindingRegistrar#registerDubboConfigBean

这里就是通过BeanDefinitionBuilder生成一个指定类型的空的beanDefinition并注册到spring容器中。

在这里插入图片描述

1.1.7.4、DubboConfigBindingRegistrar#registerDubboConfigBindingBeanPostProcessor

  1. 这里为我们刚刚每个注册的配置bean都同样注册一个DubboCOnfigBindingBeanPostProcessor类型的的bean后置处理器
  2. 这里首先生成一个DubboConfigBindingBeanPostProcessor类型的BeanDefinitionBuilder
  3. 然后这里会设置构造器参数值,把前缀和beanName都传进去,这里的前缀如:dubbo.registries.r2beanName如:r2,这里设置构造器参数的value,那么spring帮我们创建bean的时候就会调用对应的构造器把参数值传进去
  4. 通过BeanDefinitionBuilder生成DubboConfigBindingBeanPostProcessorBeanDefinition并注册到spring容器中。

在这里插入图片描述

1.1.7.5、DubboConfigBindingRegistrar#registerDubboConfigBeanCustomizers

这里会注册namePropertyDefaultValueDubboConfigBeanCustomizer的bean到spring容器中,这里后续DubboConfigBindingBeanPostProcessor处理逻辑中会用到。

在这里插入图片描述

1.1.7.6、DubboConfigBindingBeanPostProcessor#postProcessBeforeInitialization

  1. 我们在上面会给每个配置bean都生成一个后置处理器,那么在spring容器的生命周期中就会调用到后置处理器的postProcessBeforeInitialization方法,我们来看下DubboConfigBindingBeanPostProcessorpostProcessBeforeInitialization方法
  2. 这里会判断beanName是否一致,只处理关联的那个bean
  3. 这里会调用bind方法从properties中获取值并设置到DubboConfig对象中
  4. 设置dubboConfig对象的name属性,设置为beanName

在这里插入图片描述

1.1.7.7、DubboConfigBindingBeanPostProcessor#bind

  1. 这里会调用dubboConfigBinder的bind方法,我们看下dubboConfigBinder是啥时候构造出来的,他的bind方法是如何实现数据绑定的。

在这里插入图片描述

我们看到在DubboConfigBindingBeanPostProcessor#afterPropertiesSet方法会进行初始化操作,这个方法也是spring提供的回调方法,会在属性设置前调用到这个方法

在这里插入图片描述

这里initDubboConfigBinder方法首先会从spring容器中获取DubboConfigBinder类型的bean,如果获取不到就创建默认的也就是DefaultDubboConfigBinder。

在这里插入图片描述在这里插入图片描述

  1. 这里initConfigBeanCustomizers方法会从spring容器中获取DubboConfigBeanCustomizer类型的所有bean实现,这里最少会有一个,之前在DubboConfigBindingRegistrar中注册的namePropertyDefaultValueDubboConfigBeanCustomizer
  2. 然后设置到configBeanCustomizers属性中,并且会按照order进行排序.

在这里插入图片描述

1.1.7.8、DefaultDubboConfigBinder#bind

  1. 从上面我们知道如果我们没有注入DubboCOnfigBinder,则默认是DefaultDubboConfigBinder
  2. 这里会创建DataBinder,这个是spring提供的,用来实现数据绑定
  3. 这里设置忽略无用的属性和不能解析的属性
  4. 从properties中获取指定前缀的属性
  5. 把perperties转成MutablePropertyValues,调用dataBinder#bind方法执行绑定操作,这里会把MutablePropertyValues中的配置绑定到dubboConfig中。

在这里插入图片描述

1.1.7.9、DubboConfigBindingBeanPostProcessor#customize

  1. 这里会遍历从spring容器中获取的所有configBeanCustomizers,并调用其customize方法
  2. 这里如果我们没有配置,默认只有一个NamePropertyDefaultValueDubboConfigBeanCustomizer

在这里插入图片描述

这里其实就是判断如果DubboConfig中有name属性,则判断如果name属性如果没有设置值,则反射调用其set方法把beanName设置到name属性中。

在这里插入图片描述

1.2、DubboComponentScan注解

这里通过Import导入了DubboComponentScanRegistrar

在这里插入图片描述

1.2.1、DubboComponentScanRegistrar#registerBeanDefinitions

  1. 获取包扫描路径
  2. 注册处理@Service注解的后置处理器
  3. 注册处理@Reference注解的后置处理器

在这里插入图片描述

1.2.2、DubboComponentScanRegistrar#getPackagesToScan

  1. 获取DubboComponentScan注解中配置的属性
  2. 获取value属性,并把包路径数组转成set,可以对重复的包路径去重
  3. 如果指定了basePackageClasses,那么说明需要对这些类所在包路径设置到set中
  4. 如果都没指定包路径,则使用当前标注了@DubboComponentScan注解所在类的包路径作为基础包扫描路径。

在这里插入图片描述

1.2.3、DubboComponentScanRegistrar#registerServiceAnnotationBeanPostProcessor

  1. 注册ServiceAnnotationBeanPostProcessor后置处理器到spring容器中,并制定构造器的参数值为包扫描路径,这里spring会在生成bean的时候会调用构造方法设置进去

在这里插入图片描述

1.2.4、DubboComponentScanRegistrar#registerReferenceAnnotationBeanPostProcessor

  1. 注册registerReferenceAnnotationBeanPostProcessor后置处理器到spring容器中

在这里插入图片描述

1.2.5、ServiceAnnotationBeanPostProcessor#postProcessBeanDefinitionRegistry

  1. ServiceAnnotationBeanPostProcessor是一个BeanDefinitionRegistryPostProcessor,spring会回调他的postProcessBeanDefinitionRegistry方法来让用户修改BeanDefinition
  2. 这里会获取用户注解配置的包扫描
  3. 调用registerServiceBeans注册ServiceBean
    在这里插入图片描述

1.2.5.1、ServiceAnnotationBeanPostProcessor#postProcessBeanDefinitionRegistry

这里就是做了下占位符的处理,因为有可能包路径中有占位符例:xxx.${xx}…xxx。

在这里插入图片描述

1.2.5.2、ServiceAnnotationBeanPostProcessor#postProcessBeanDefinitionRegistry

  1. 这里首先创建DubboClassPathBeanDefinitionScanner,用来执行包扫描
  2. 从registry中解析出BeanNameGenerator
  3. 设置的DubboClassPathBeanDefinitionScanner的beanNameGenerator为刚刚解析出来的BeanName生成器
  4. 给scanner设置IncludeFilter,表示只扫描标注了Dubbo中的@Service注解的类
  5. 遍历包路径,执行扫描操作,把扫描出来的BeanDifinition转换成BeanDefinitionHolder
  6. 遍历BeanDefinitionHolders,注册ServiceBean

在这里插入图片描述

1.2.5.3、ServiceAnnotationBeanPostProcessor#resolveBeanNameGenerator

  1. 判断如果BeanDefinitionRegistry是SingletonBeanRegistry类型,则获取internalConfigurationBeanNameGenerator返回
  2. 如果不是SingletonBeanRegistry或者从容器中没有获取到internalConfigurationBeanNameGenerator则使用AnnotationBeanNameGenerator

在这里插入图片描述

1.2.5.4、ServiceAnnotationBeanPostProcessor#findServiceBeanDefinitionHolders

  1. 获取出来packageToScan路径下标注了@Service的BeanDefinition
  2. 把扫描出来的BeanDefinition转换成BeanDefinitionHolder,Holder中包含BeanDefinition和BeanName

在这里插入图片描述

1.2.5.5、ServiceAnnotationBeanPostProcessor#registerServiceBean

  1. 从beanDefinitionHolde中解析出来对应的beanClass
  2. 从BeanClass上获取标注的@Service注解信息
  3. 从beanClass和@Service注解信息中解析出来对应实现的接口的class
  4. 从从beanDefinitionHolder中获取BeanName,构造ServiceBean的Definition,这个ServiceBean用来存储这个服务提供者的元数据信息
  5. 生成ServiceBean的BeanName
  6. 如果没有冲突,则会添加到spring容器中

在这里插入图片描述

1.2.5.5、ServiceAnnotationBeanPostProcessor#resolveClass

  1. 这里从BeanDefinition获取到对应的BeanClassName,然后通过BeanClassName解析出来对应的class对象

在这里插入图片描述

1.2.5.6、ServiceAnnotationBeanPostProcessor#resolveServiceInterfaceClass

  1. 首先拿@service注解中配置的interfaceClass属性,如果没有指定,在判断用户有没有在注解中指定interfaceName,如果指定了,则尝试解析出interfaceName对应的class返回
  2. 如果注解中没有配置,则获取到当前BeanClass实现的所有接口类,然后获取第一个

在这里插入图片描述

1.2.5.6、ServiceAnnotationBeanPostProcessor#buildServiceBeanDefinition

  1. 首先通过BeanDefinitionBuilder生成一个空的ServiceBean的BeanDefinition
  2. 这里获取BeanDefinition的propertyValues,然后设置忽略的属性名,因为这些都是对象类型,是我们之前解析配置文件生成的配置类,已经放到spring容器中,需要通过注入的方式特殊赋值
  3. 给BeanDefinition的propertyValues添加一个PropertyValues是AnnotationPropertyValuesAdapter,这个可以从environment获取对应的配置,后续spring在进行属性注入的时候会自动填充
  4. 下面就是调用addPropertyReference,这里会从spring容器中找到对应name的bean,然后把对应的bean设置到其属性中

在这里插入图片描述
在这里插入图片描述

1.2.5.7、ServiceAnnotationBeanPostProcessor#generateServiceBeanName

这里serviceBeanName的生成规则就是拼接了接口名+分组名+版本号生成一个beanName

在这里插入图片描述
在这里插入图片描述

1.2.5.8、ServiceBean#onApplicationEvent

  1. 在上面我们已经把ServiceBean注册到Spring容器中,那么他是什么时候进行服务暴露的,注册到注册中上,供外部服务调用,从下图我们可以看到他是继承了很多接口,其中一个就是ApplicationListener,并且监听的是容器刷新完成的时间。
  2. 那么Spring容器在刷新完成的时候就会回调监听器的onApplicationEvent方法,在这里会进行dubbo服务的导出操作,这个后续我们再进行分析。

在这里插入图片描述
在这里插入图片描述

1.2.6、ReferenceAnnotationBeanPostProcessor

  1. 这里他继承了AnnotationInjectedBeanPostProcessor,并且指定了要进行自动注入的注解是@Reference注解,这个AnnotationInjectedBeanPostProcessor的回调时机是在Bean属性填充完毕后,这里可以类比@Autowried注解,也是会有一个xxxProcessor来进行自动注入的逻辑

在这里插入图片描述

1.2.6.1 、AnnotationInjectedBeanPostProcessor#postProcessPropertyValues

  1. 这里首先会找到Bean所有标注了@Reference注解的字段和方法
  2. 然后对字段、方法进行反射绑定

在这里插入图片描述

1.2.6.2 、AnnotationInjectedBeanPostProcessor#findInjectionMetadata

  1. 这里首先从缓存中获取当前bean的注入元数据信息
  2. 如果缓存中没有,则会调用buildAnnotatedMetadata方法构造注解元数据

在这里插入图片描述

1.2.6.3 、AnnotationInjectedBeanPostProcessor#buildAnnotatedMetadata

  1. 这里首先查找这个类标注了@Reference注解的属性元素
  2. 再查找这个类标注了@Reference注解的方法元素
  3. 组装成AnnotatedInjectionMetadata返回

在这里插入图片描述

1.2.6.4 、AnnotationInjectedBeanPostProcessor#buildAnnotatedMetadata

  1. 这里就是遍历这个类对应的所有属性,判断上面有没有标注@Reference注解
  2. 判断如果有标注注解,如果修饰符是static,那么也不支持
  3. 如果满足条件则加入到元素列表中返回

在这里插入图片描述

1.2.6.5 、AnnotationInjectedBeanPostProcessor#findAnnotatedMethodMetadata

  1. 这里遍历类中的所有方法,这里有可能方法是个泛型方法,因为泛型在编译阶段会进行类型擦除,Java编译器会将类型参数替换为其上界(类型参数中extends子句的类型),如果上界没有定义,则默认为Object,当一个子类在继承(或实现)一个父类(或接口)的泛型方法时,在子类中明确指定了泛型类型,那么在编译时编译器会自动生成桥接方法,这样是为了避免子父类方法签名不一致,就在子类自动生成一个与父类的方法签名一致的桥接方法
  2. 所以这里会判断如果是桥接方法就找到被桥接的方法,然后判断被桥接的方法是否可见,方法上面有没有标注@Reference注解
  3. 如果有注解,则判断是不是静态,不支持静态方法,也不支持无参方法,因为这样没法进行注入了,不知道注入啥类型的
  4. 把符合条件的方法收集返回

在这里插入图片描述

1.2.6.5 、InjectionMetadata#inject

  1. 在上面已经查询到了并组装成InjectionMetadata,这里会调用inject方法执行注入操作
  2. 这里是spring的源码,会遍历每个element,并调用其inject方法

在这里插入图片描述

1.2.6.6 、InjectionMetadata#inject

在上面调用每个element的inject方法就会调用到element具体的实现,是方法的还是属性的

在这里插入图片描述

1.2.6.6.1 、AnnotatedFieldElement#inject
  1. 获取属性类型
  2. 获取注入的对象
  3. 通过反射设置到属性中

在这里插入图片描述

1.2.6.6.2、AnnotatedFieldElement#inject
  1. 获取属性类型
  2. 获取注入的对象
  3. 通过反射设置

在这里插入图片描述

1.2.6.7 、AnnotationInjectedBeanPostProcessor#getInjectedObject

  1. 首先构造缓存key,从缓存中获取
  2. 如果缓存中不存在,则调用doGetInjectedBean获取注入的对象

在这里插入图片描述

1.2.6.8 、ReferenceAnnotationBeanPostProcessor#doGetInjectedBean

  1. 首先构造serviceBean的名字,通过接口+分组+版本构造
  2. 调用buildReferenceBeanIfAbsent方法,生成ReferenceBean对象
  3. 放入缓存中
  4. 生成代理对象

在这里插入图片描述

1.2.6.9 、ReferenceAnnotationBeanPostProcessor#buildReferenceBeanIfAbsent

  1. 先从缓存中获取referenceBean
  2. 如果缓存中没有,则通过ReferenceBeanBuilder生成一个referenceBean

在这里插入图片描述

1.2.6.9.1 、ReferenceBeanBuilder#build
  1. 这里checkDependencies是个空方法
  2. 调用doBuild创建一个ReferenceBean
  3. 调用configureBean配置ReferenceBean的相关属性

在这里插入图片描述

1.2.6.9.2 、ReferenceBeanBuilder#doBuild
  1. 这里直接创建一个ReferenceBean返回

在这里插入图片描述

1.2.6.9.3、AbstractAnnotationConfigBeanBuilder#doBuild
  1. ConfigureBean的前置操作
  2. 然后设置注册中心配置,监控中心配置,应用配置,模块配置等
  3. ConfigureBean的后置操作

在这里插入图片描述

1.2.6.9.4、ReferenceBeanBuilder#preConfigureBean
  1. 这里又使用到了DataBinder来给referenceBean来做数据绑定
  2. 这里给filter和listener属性注册了StringTrimmerEditor,他会帮助格式化String,去除前后空格
  3. 处理parameters属性,通过自定义的PropertyEditorSupport,把String处理成map
  4. 调用dataBinder#bind方法,这里会自动给referenceBean绑定配置文件中的相关配置

在这里插入图片描述

1.2.6.9.5、AbstractAnnotationConfigBeanBuilder#configureRegistryConfigs

这里设置配置的逻辑一致,都是从@Reference注解中获取对应的配置名,然后从spring容器中找到对应的配置Bean,然后设置到属性中。

在这里插入图片描述

1.2.6.9.6、ReferenceBeanBuilder#postConfigureBean
  1. 这里还是设置一些属性到ReferenceBean中,其中具体就不细看了,和上面类似

在这里插入图片描述

1.2.6.10 、ReferenceAnnotationBeanPostProcessor#cacheInjectedReferenceBean

这里就是把对应的注入点和对应的注入值放入缓存中

在这里插入图片描述

1.2.6.11 、ReferenceAnnotationBeanPostProcessor#buildProxy

  1. 调用buildInvocationHandler方法构造一个InvocationHandler
  2. 创建一个proxy对象返回,这里需要代理对象是因为Dubbo在调用的时候就算是本地服务也有负载均衡,注册中心等一系列其他的逻辑,因此不能直接返回服务实现类,而是返回代理对象,公共的操作让代理对象去执行

在这里插入图片描述

1.2.6.12 、ReferenceAnnotationBeanPostProcessor#buildInvocationHandler

.1 先从缓存中获取,如果缓存中没有就创建一个
2. 判断当前spring容器中有没有包含着这个引用的bean,如果有说明是本地调用,则缓存起来
3. 如果是远程调用,则会调用ReferenceBeanInvocationHandler#init方法

在这里插入图片描述

1.2.6.12 、ReferenceBeanInvocationHandler#init

  1. 这里会调用referenceBean#get方法,会返回一个代理对象
  2. 这里#referenceBean#get方法是服务引入的核心逻辑,我们后续章节剖析

在这里插入图片描述
最后这里返回的代理对象会被设置到对应标注了@Reference的属性中,然后调用其方法都会走到代理对象这里,Dubbo会在这里面做一系列远程调用,服务容错,服务逻辑的逻辑。

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

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

相关文章

软考中级-面向对象

面向对象基础(1)类类分为三种:实体类(世间万物)、接口类(又称边界类,提供用户与系统交互的方式)、控制类(前两类之间的媒介)。对象:由对象名数据&…

【jumpServer 功能梳理】

用户管理 1.1 用户列表 创建jumpServe 账号 ;角色分为用户 管理员;更新账号信息;查看用户详情以及授权的资产; 1.2 用户组 用户组,这个组的意义在于用一个统称对接资源;用户组包含多个用户,可以操作增加删除…

LeetCode初级算法题:两数之和+斐波拉契数列多种java解法

目录7 两数之和题目描述:解题思路与代码暴力解法:解法一:二分查找解法二:双指针2 斐波那契数列题目描述:解题思路与代码![请添加图片描述](https://img-blog.csdnimg.cn/d06a95d7989b4794bd7f5f02fbd6f87e.png)解法一&…

spring之使用Spring的AOP

文章目录前言一、准备工作1、添加相应的依赖2、添加相应的命名空间3、创建目标类4、创建切面二、使用AOP1.在切面类中编写增强代码以及切点表达式2、开启aspectj的自动代理3、测试类4、测试结果前言 Spring对AOP的实现包括以下三种方式 1、Spring框架结合AspectJ框架实现的AOP…

自抗扰控制ADRC之反馈控制律(NLSEF)

目录 前言 1.非线性状态误差反馈控制律(NLSEF) 1.1 控制律形式 1.2 控制量的生成(或者说扰动的补偿) 1.2.1补偿形式① 1.2.1补偿形式② 2.仿真分析 2.1仿真模型 2.2仿真结果 前言 前面的两篇博客依次介绍了TD微分跟踪器安排过渡过程、扩张观测器: 自抗扰…

用腾讯云同步Obsidian笔记

介绍 之前用gitee同步OB笔记,同时做图床。但由于git系产品设置起来相对复杂,且后续可能有外链过审等问题。周五被同事小姐姐安利了用腾讯云COS,试了一下,果然不错。其主要优点如下: 设置简单,学习成本低&…

WSL(Windows Subsystem for Linux)

一、WSL优势 •传统方式:获取Linux操作系统环境,必须安装完整的虚拟机,如VMware•WSL:以非常轻量化的方式,得到Linux系统环境总结:WSL更方便,简单、好用、轻量化、省内存 二、什么是WSL ①不…

Go语言基础(十五):垃圾回收机制(三色标记)

文章目录一、标记清除(三色标记)大致原理1、标记细节2、root对象二、垃圾回收触发机制垃圾回收(Garbage Collection),是一种自动管理内存的机制。传统编程语言(如C/C)需要开发者对无用内存资源进…

Android实例仿真之三

目录 四 Android架构探究 五 大骨架仿真 六 Android实例分析思路拓展 四 Android架构探究 首先,Android系统所带来的好处,就在于它本身代码的开放性,这提供了一个学习、借鉴的平台。这对分析仿真而言,本身就是一大利好&#xf…

[JAVA安全]Spring Messaging之CVE-2018-1270

漏洞简介 Spring 框架中通过spring-messaging 模块来实现 STOMP (Simple Text-Orientated Messaging Protocol),STOMP是一种封装 WebSocket的简单消息协议。攻击者可以通过建立WebSocket连接并发送一条消息造成远程代码执行, spring-messagin…

C++笔记 模板的进阶知识

目录 1. 非类型模板参数 2.模板的特化 2.1 函数模板的特化 2.2 类模板的特化 2.2.1 全特化 2.2.2 偏特化 3.模板的分离编译 3.1 什么是分离编译? 3.2 模板的分离编译 4.模板的总结 模板的初阶内容:(594条消息) C模板的原理和使用_全貌的博客-CSD…

【干货】如何打造HR无法拒绝的简历?测试开发大牛带手把手你写简历!

通过率90%,优秀的软件测试简历长什么样? 也许口才好的人会觉得简历不重要,能说就行了,那是因为你没有体会过石沉大海的感觉! 很多人觉得疑惑,为什么我投了那么多简历,都没有接到面试通知&…

加油站会员管理小程序实战开发教程15 完结篇

这篇是本次实战课程的最后一篇,我们在上篇还有两个问题没解决。一个是会员卡类型显示不对,一个是不同的会员卡我们希望背景色显示不同。我们先处理一下这两个问题 1 显示会员卡类型 在列表上直接显示会员卡类型,目前显示的是数字,这个是因为枚举类型导致的。枚举类型在数…

关于vb6无边框的窗体开发遇到的部分问题的解决方案

为了美化或自定义窗体,通常会把窗体做成无边框形式,使用无边框窗体会存在一些问题的,以vb为例,当窗体borderstyle设置为0时,会出现以下问题:1.任务栏不再出现程序图标 2.窗体无法拖行移动 3.窗体无法拖动缩放&#…

WampServer安装教程

文章目录简介:官网地址安装步骤:我是阿波,学习PHP记录一下笔记,如果对你有帮助,欢迎一键三连,谢谢! 简介: WampServer是一个用于Windows操作系统的Web开发环境,其名称来…

10- 天猫用户复购预测 (机器学习集成算法) (项目十) *

项目难点 merchant: 商人重命名列名: user_log.rename(columns{seller_id:merchant_id}, inplaceTrue)数据类型转换: user_log[item_id] user_log[item_id].astype(int32)主要使用方法: xgboost, lightbm竞赛地址: 天猫复购预测之挑战Baseline_学习赛_天池大赛-阿里云天池…

java并发编程原理1(原子性,可见行,有序性,volatile,synchronized)

一、原子性: 1.1 Java中如何实现线程安全? 多线程操作共享数据出现的问题。 锁: 悲观锁:synchronized,lock乐观锁:CAS 可以根据业务情况,选择ThreadLocal,让每个线程玩自己的数据。 1.2 C…

内大-oj练习题(2期)

内大oj2期 1. 输出一个数的质数因子2. 寻找完数3. 圆的面积4. 求同存异5. 2的k进制数6. 输出排序序列6. DNA算法1. 输出一个数的质数因子 介绍 因子,例如 33=9 (3就是因子); 19=9(1,9就是因子) 质数, 只能被1和本身整除的数 题目 代码 #include <iostream>

Windows7下使用VMware11.1.1安装ubuntu-16.04.7

一、说明二、安装说明三、安装步骤详解1、先安装VMware软件2、创建虚拟机3、编辑虚拟机4、开启虚拟机&#xff0c;初始化Linux系统一、说明 虽然VMware和ubuntu最新版已经很高了&#xff0c;我这电脑由于是win7配值还低&#xff0c;所以采用低版本来安装 VMware版本&#xff1…

C++Primer15.5节练习

练习15.18&#xff1a; Base* p &d1&#xff1a;合法 p &d2&#xff1a;不合法&#xff0c;只有当派生类公有地继承基类时&#xff0c;用户代码才能使用派生类向基类的转换 p &d3&#xff1a;不合法&#xff0c;只有当派生类公有地继承基类时&#xff0…