Spring源码分析(十)Bean实例化(下)

目录

    • 1.1 循环依赖
    • 1.2 属性填充
      • 1.2.1 populateBean方法
      • 1.2.2 initializeBean方法
        • 执行Aware方法
        • 执行BeanPostProcessor后置处理器的前置处理方法
        • 执行初始化方法
        • 执行BeanPostProcessor后置处理器的后置处理方法:postProcessAfterInitialization(),允许对bean实例进行包装
    • 1.3 根据 scope 注册 bean

  • 官网:Home
  • 参考书籍:Spring源码深度解析-郝佳编著-微信读书

AbstractAutowireCapableBeanFactory
上一节我们详细的解释了Bean的实例化的后置处理,我们接着往下看doCreateBean的方法,依赖的处理

// 是否需要提前曝光,用来解决循环依赖时使用boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&isSingletonCurrentlyInCreation(beanName));if (earlySingletonExposure) {if (logger.isTraceEnabled()) {logger.trace("Eagerly caching bean '" + beanName +"' to allow for resolving potential circular references");}// 注释 5.2 将缓存中的 bean 信息更新,解决循环依赖 第二个参数是回调接口,实现的功能是将切面动态织入 beanaddSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));}

依赖注入概念:就是A在getBean初始化时,如果依赖了另一个bean B,那么会先去调用B的getBean初始化B。但是B再去getBean时又依赖A。那么就出现了死循环。Spring按照域(Scope)进行处理,如果是非单利模式则抛出异常。

1.1 循环依赖

我们看到上面的代码虽然短短几行,但是解决了循环依赖的问题,我们新总体讲述一下大体步骤:
虽然只有短短的几行代码,但是这是单利模式循环依赖的实现。上面判断了三个条件:
1、当前Bean为单例:Scope
2、容器级别的allowCircularReferences(是否允许循环依赖),默认为true
3、当前Bean是否标记为正在创建中,存放在(singletonsCurrentlyInCreation容器中)
如果允许提前暴露,通过addSingletonFactory()方法将生成bean的工厂ObjectFactory添加到三级缓存(singletonFactories)中,这是Spring解决循环依赖非常关键的代码。
DefaultSingletonBeanRegistry

protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {Assert.notNull(singletonFactory, "Singleton factory must not be null");// 加锁synchronized (this.singletonObjects) {// 1、如果一级缓存中不存在当前beanName的时候,才能进if判断if (!this.singletonObjects.containsKey(beanName)) {// 2、将beanName => ObjectFactory的映射关系添加到三级缓存中,注意添加的是创建bean的对象工厂singletonFactorythis.singletonFactories.put(beanName, singletonFactory);// 3、从二级缓存中移除当前beanNamethis.earlySingletonObjects.remove(beanName);// 4、将beanName添加到已注册单例集合中this.registeredSingletons.add(beanName);}}
}
  • 其实是在DefaultSingletonBeanRegistry#getSingleton(java.lang.String, boolean)方法中使用到,singletonObject = singletonFactory.getObject()
  • 执行singletonFactory.getObject()的时候,实际上就是执行getEarlyBeanReference()方法获取早期bean的对象引用。

我们先简单看看三级缓存代码部分,后面单独文章详细介绍:
DefaultSingletonBeanRegistry

//  一级缓存:用于保存beanName和创建bean实例之间的关系,beanName -> bean instance
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);// 三级缓存:用于保存beanName和创建bean的工厂之间的关系,beanName -> ObjectFactory
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);// 二级缓存:用于保存beanName和创建bean实例之间的关系,beanName -> bean instance
// 与一级缓存的区别:当一个单例bean被放在二级缓存中后,当bean还在创建过程中,就可以通过getBean方法获取到了,目的是用来检测循环引用
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
  • getEarlyBeanReference():获取早期访问指定 bean的引用
/*** 获取早期访问指定 bean 的引用,通常用于解析循环引用* @param beanName* @param mbd* @param bean* @return*/protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {Object exposedObject = bean;// 1、如果bean 定义不是“合成的”,并且工厂中存在创建时应用于单例 bean 的 InstantiationAwareBeanPostProcessor后置处理器,才会进入下面的逻辑if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {// 2、获取工厂中所有已注册的BeanPostProcessor后置增强器for (BeanPostProcessor bp : getBeanPostProcessors()) {// 3、判断是否属于SmartInstantiationAwareBeanPostProcessor类型if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;// 4、类型匹配的话,则执行SmartInstantiationAwareBeanPostProcessor的getEarlyBeanReference()方法获取bean的早期引用// getEarlyBeanReference()方法: 此回调使后处理器有机会尽早暴露包装器 - 即在目标 bean 实例完全初始化之前, 默认实现是返回原始的bean对象exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);}}}// 5、如果不存在SmartInstantiationAwareBeanPostProcessor,则直接返回原始的bean对象return exposedObject;}

:::warning
注意,上述代码中getEarlyBeanReference()方法并不是在这里就执行,这里只是将【() -> getEarlyBeanReference(beanName, mbd, bean)】这个函数式接口作为创建bean的对象工厂,添加到三级缓存中而已,后续解决循环依赖的时候,就会从三级缓存中拿出这个对象工厂,即执行ObjectFactory.getObject()方法的时候,就会回调getEarlyBeanReference(beanName, mbd, bean)方法,获取到提前暴露的bean的早期引用,从而解决循环依赖。
:::

1.2 属性填充

经过上面的一些了过程,终于来到实例化Bean

    	// Initialize the bean instance.Object exposedObject = bean;try {// 对 bean 进行填充,将各个属性值注入// 如果存在对其它 bean 的依赖,将会递归初始化依赖的 beanpopulateBean(beanName, mbd, instanceWrapper);// 调用初始化方法,例如 init-methodexposedObject = initializeBean(beanName, exposedObject, mbd);}catch (Throwable ex) {if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {throw (BeanCreationException) ex;}else {throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);}}

首先我们来看看一个关键的方法populateBean

1.2.1 populateBean方法

AbstractAutowireCapableBeanFactory

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {// 1、针对bean的包装器是否为空、是否存在为此 bean 定义的属性值,做不同的处理if (bw == null) {// 如果bean的包装器为空,但是又存在为此 bean 定义的属性值,Spring则会抛出BeanCreationException异常// 因为属性填充就是要给BeanWrapper 中的 bean 实例中的属性进行赋值的过程,存在属性,但是BeanWrapper为空,也就是BeanWrapper 中的 bean 实例为空,那么显然不行if (mbd.hasPropertyValues()) {throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");} else {// 如果没有为此 bean 定义的属性值,即没有可填充的属性,则直接返回// Skip property population phase for null instance.return;}}// Give any InstantiationAwareBeanPostProcessors the opportunity to modify the// state of the bean before properties are set. This can be used, for example,// to support styles of field injection.// InstantiationAwareBeanPostProcessor后置处理器:可以在属性设置前修改bean// 2、如果bean定义不是合成的,并且工厂中存在创建时应用于单例 bean 的 InstantiationAwareBeanPostProcessor后置处理器,则需要处理执行它的postProcessAfterInstantiation()方法if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {// 获取到bean工厂所有已经注册的BeanPostProcessorfor (BeanPostProcessor bp : getBeanPostProcessors()) {// 判断是否属于InstantiationAwareBeanPostProcessor类型if (bp instanceof InstantiationAwareBeanPostProcessor) {InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;// 如果类型匹配的话,将会执行InstantiationAwareBeanPostProcessor的postProcessAfterInstantiation()方法// postProcessAfterInstantiation()方法:在bean实例化后,属性填充之前被调用,允许修改bean的属性,默认实现是返回trueif (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {// 如果postProcessAfterInstantiation()方法返回false,则跳过后面的属性填充过程return;}}}}// 3、获取到bean定义中封装好的属性值PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);// 4、根据设置的自动注入方式(名称或者类型)获取属性bean(递归getBean)存入PropertyValues中int resolvedAutowireMode = mbd.getResolvedAutowireMode();if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {MutablePropertyValues newPvs = new MutablePropertyValues(pvs);// 根据名称自动注入// Add property values based on autowire by name if applicable.if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {autowireByName(beanName, mbd, bw, newPvs);}//根据类型自动注入// Add property values based on autowire by type if applicable.if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {autowireByType(beanName, mbd, bw, newPvs);}pvs = newPvs;}// hasInstAwareBpps:工厂是否存在将在创建时应用于单例 bean 的 InstantiationAwareBeanPostProcessor后置处理器boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();// needsDepCheck:是否需要进行依赖检查boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);PropertyDescriptor[] filteredPds = null;// 5、如果存在InstantiationAwareBeanPostProcessor后置处理器,需要执行InstantiationAwareBeanPostProcessor的postProcessProperties()以及postProcessPropertyValues()方法回调if (hasInstAwareBpps) {if (pvs == null) {pvs = mbd.getPropertyValues();}// 执行InstantiationAwareBeanPostProcessor的postProcessProperties()以及postProcessPropertyValues()方法回调// postProcessProperties(): 允许对填充前的属性进行处理(如对属性的验证)// postProcessPropertyValues(): 对属性值进行修改,通过基于原始的PropertyValues创建一个新的MutablePropertyValues实例,添加或删除特定的值。// 不过目前方法已经被标记为过期,在后续Spring版本中可能会被删除for (BeanPostProcessor bp : getBeanPostProcessors()) {if (bp instanceof InstantiationAwareBeanPostProcessor) {InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);if (pvsToUse == null) {if (filteredPds == null) {filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);}pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);if (pvsToUse == null) {return;}}pvs = pvsToUse;}}}// 6、执行依赖检查,对应depend-on属性if (needsDepCheck) {if (filteredPds == null) {filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);}// 依赖检查,对应depend-on属性checkDependencies(beanName, mbd, filteredPds, pvs);}// 7、属性填充的具体过程,即将属性值赋值到beanWrapper中bean实例的具体属性中if (pvs != null) {// 开始填充属性值applyPropertyValues(beanName, mbd, bw, pvs);}
}

我们来梳理一下他的流程:

  • 针对bean的包装器是否为空、是否存在为此 bean 定义的属性值,做不同的处理。
  • 如果bean的包装器为空,但是又存在为此 bean 定义的属性值,Spring则会抛出BeanCreationException异常;如果没有为此 bean 定义的属性值,即没有可填充的属性,则直接返回
  • 如果bean定义不是合成的,并且工厂中存在创建时应用于单例 bean 的 InstantiationAwareBeanPostProcessor后置处理器,则需要处理执行它的postProcessAfterInstantiation()方法
  • 获取到bean定义中封装好的属性值
  • 根据设置的自动注入方式(名称或者类型)获取属性bean(递归getBean)存入PropertyValues中
  • 如果存在InstantiationAwareBeanPostProcessor后置处理器,需要执行InstantiationAwareBeanPostProcessor的postProcessProperties()以及postProcessPropertyValues()方法回调
  • 执行依赖检查,对应depend-on属性
  • 属性填充的具体过程,即将属性值赋值到beanWrapper中bean实例的具体属性中

1:Bean包装器判断

	// 1、针对bean的包装器是否为空、是否存在为此 bean 定义的属性值,做不同的处理if (bw == null) {// 如果bean的包装器为空,但是又存在为此 bean 定义的属性值,Spring则会抛出BeanCreationException异常// 因为属性填充就是要给BeanWrapper 中的 bean 实例中的属性进行赋值的过程,存在属性,但是BeanWrapper为空,也就是BeanWrapper 中的 bean 实例为空,那么显然不行if (mbd.hasPropertyValues()) {throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");} else {// 如果没有为此 bean 定义的属性值,即没有可填充的属性,则直接返回// Skip property population phase for null instance.return;}}

2:调用**postProcessAfterInstantiation方法**

if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {// 获取到bean工厂所有已经注册的BeanPostProcessorfor (BeanPostProcessor bp : getBeanPostProcessors()) {// 判断是否属于InstantiationAwareBeanPostProcessor类型if (bp instanceof InstantiationAwareBeanPostProcessor) {InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;// 如果类型匹配的话,将会执行InstantiationAwareBeanPostProcessor的postProcessAfterInstantiation()方法// postProcessAfterInstantiation()方法:在bean实例化后,属性填充之前被调用,允许修改bean的属性,默认实现是返回trueif (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {// 如果postProcessAfterInstantiation()方法返回false,则跳过后面的属性填充过程return;}}}}

3:封装值

// 3、获取到bean定义中封装好的属性值
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);

4:根据设置的自动注入方式(名称或者类型)获取属性bean(递归getBean)存入PropertyValues中(重点理解)

    	// 4、根据设置的自动注入方式(名称或者类型)获取属性bean(递归getBean)存入PropertyValues中int resolvedAutowireMode = mbd.getResolvedAutowireMode();if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {MutablePropertyValues newPvs = new MutablePropertyValues(pvs);// 根据名称自动注入// Add property values based on autowire by name if applicable.if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {autowireByName(beanName, mbd, bw, newPvs);}//根据类型自动注入// Add property values based on autowire by type if applicable.if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {autowireByType(beanName, mbd, bw, newPvs);}pvs = newPvs;}// hasInstAwareBpps:工厂是否存在将在创建时应用于单例 bean 的 InstantiationAwareBeanPostProcessor后置处理器boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();// needsDepCheck:是否需要进行依赖检查boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);

首先我们看看Spring提供了那几种注入方式:
**AutowireCapableBeanFactor**y

int AUTOWIRE_NO = 0;
// 名称
int AUTOWIRE_BY_NAME = 1;
// 类型 	
int AUTOWIRE_BY_TYPE = 2;
// 构造器
int AUTOWIRE_CONSTRUCTOR = 3;
// 已废弃 ,自动
@Deprecated
int AUTOWIRE_AUTODETECT = 4;

首先获取Bean的注入方式:
AbstractBeanDefinition

	public int getResolvedAutowireMode() {// 自动注入if (this.autowireMode == AUTOWIRE_AUTODETECT) {// Work out whether to apply setter autowiring or constructor autowiring.// If it has a no-arg constructor it's deemed to be setter autowiring,// otherwise we'll try constructor autowiring.Constructor<?>[] constructors = getBeanClass().getConstructors();for (Constructor<?> constructor : constructors) {// 构造器参数为0if (constructor.getParameterCount() == 0) {// 类型注入return AUTOWIRE_BY_TYPE;}}// 构造器注入return AUTOWIRE_CONSTRUCTOR;}else {return this.autowireMode;}}

我们首先来看看通过名称注入:

protected void autowireByName(String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {// 1、获取需要注入的属性名称数组,注意只获取不是“简单”属性类型(基础类型、枚举、Number等)的那些属性String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);// 2、循环需要注入的属性,根据名称自动注入for (String propertyName : propertyNames) {// 3、判断是否存在名称为propertyName的bean或者bean定义,如果当前工厂中没找到,还会递归所有的父工厂去查找if (containsBean(propertyName)) {// 4、通过getBean从工厂中获取到名称为propertyName的bean实例Object bean = getBean(propertyName);// 5、将propertyName以及对应的属性值bean添加到MutablePropertyValues中pvs.add(propertyName, bean);// 6、注册依赖关系到两个缓存中:dependentBeanMap、dependenciesForBeanMapregisterDependentBean(propertyName, beanName);if (logger.isTraceEnabled()) {logger.trace("Added autowiring by name from bean name '" + beanName +"' via property '" + propertyName + "' to bean named '" + propertyName + "'");}} else {// 7、如果工厂以及父工厂都没有找到名称为propertyName的bean或者bean定义,则不处理这个属性if (logger.isTraceEnabled()) {logger.trace("Not autowiring property '" + propertyName + "' of bean '" + beanName +"' by name: no matching bean found");}}}}

注册Bean的依赖关系
DefaultSingletonBeanRegistry

//为指定的Bean注入依赖的Bean
public void registerDependentBean(String beanName, String dependentBeanName) {// A quick check for an existing entry upfront, avoiding synchronization...//处理Bean名称,将别名转换为规范的Bean名称String canonicalName = canonicalName(beanName);Set<String> dependentBeans = this.dependentBeanMap.get(canonicalName);if (dependentBeans != null && dependentBeans.contains(dependentBeanName)) {return;}// No entry yet -> fully synchronized manipulation of the dependentBeans Set//多线程同步,保证容器内数据的一致性//先从容器中:bean名称-->全部依赖Bean名称集合找查找给定名称Bean的依赖Beansynchronized (this.dependentBeanMap) {//获取给定名称Bean的所有依赖Bean名称dependentBeans = this.dependentBeanMap.get(canonicalName);if (dependentBeans == null) {//为Bean设置依赖Bean信息dependentBeans = new LinkedHashSet<>(8);this.dependentBeanMap.put(canonicalName, dependentBeans);}//向容器中:bean名称-->全部依赖Bean名称集合添加Bean的依赖信息//即,将Bean所依赖的Bean添加到容器的集合中dependentBeans.add(dependentBeanName);}//从容器中:bean名称-->指定名称Bean的依赖Bean集合找查找给定名称Bean的依赖Beansynchronized (this.dependenciesForBeanMap) {Set<String> dependenciesForBean = this.dependenciesForBeanMap.get(dependentBeanName);if (dependenciesForBean == null) {dependenciesForBean = new LinkedHashSet<>(8);this.dependenciesForBeanMap.put(dependentBeanName, dependenciesForBean);}//向容器中:bean名称-->指定Bean的依赖Bean名称集合添加Bean的依赖信息//即,将Bean所依赖的Bean添加到容器的集合中dependenciesForBean.add(canonicalName);}
}

a、对Bean 的属性代调用getBean()方法,完成依赖Bean 的初始化和依赖注入。
b、将依赖Bean 的属性引用设置到被依赖的Bean 属性上。
c、将依赖Bean 的名称和被依赖Bean 的名称存储在IOC 容器的集合中。
接下来看看通过类型注入:

/*** 通过类型注入* @param beanName* @param mbd* @param bw* @param pvs*/protected void autowireByType(String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {// 1、判断是否存在自定义的TypeConverter,存在则使用自定义的,否则还是使用入参指定的bwTypeConverter converter = getCustomTypeConverter();if (converter == null) {converter = bw;}Set<String> autowiredBeanNames = new LinkedHashSet<>(4);// 2、获取需要注入的属性名称数组,注意只获取不是“简单”属性类型(基础类型、枚举、Number等)的那些属性String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);for (String propertyName : propertyNames) {try {// 3、获取包装对象的特定属性的属性描述符PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);// Don't try autowiring by type for type Object: never makes sense,// even if it technically is a unsatisfied, non-simple property.if (Object.class != pd.getPropertyType()) {// 4、为指定属性的写入方法获取一个新的 MethodParameter 对象,通常指的是获取setter方法MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);// Do not allow eager init for type matching in case of a prioritized post-processor.boolean eager = !(bw.getWrappedInstance() instanceof PriorityOrdered);DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager);// 5、解析当前属性所匹配的bean实例,并把解析到的bean实例的beanName存入autowiredBeanNamesObject autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);if (autowiredArgument != null) {// 6、如果解析到的bean实例不为空的话,将propertyName以及对应的属性值autowiredArgument添加到MutablePropertyValues中pvs.add(propertyName, autowiredArgument);}for (String autowiredBeanName : autowiredBeanNames) {// 7、注册依赖关系到两个缓存中:dependentBeanMap、dependenciesForBeanMap,这里是beanName依赖了autowiredBeanNameregisterDependentBean(autowiredBeanName, beanName);if (logger.isTraceEnabled()) {logger.trace("Autowiring by type from bean name '" + beanName + "' via property '" +propertyName + "' to bean named '" + autowiredBeanName + "'");}}autowiredBeanNames.clear();}} catch (BeansException ex) {throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, propertyName, ex);}}}

5:如果存在InstantiationAwareBeanPostProcessor后置处理器,需要执行InstantiationAwareBeanPostProcessor的postProcessProperties()以及postProcessPropertyValues()方法回调

// 5、如果存在InstantiationAwareBeanPostProcessor后置处理器,需要执行InstantiationAwareBeanPostProcessor的postProcessProperties()以及postProcessPropertyValues()方法回调if (hasInstAwareBpps) {if (pvs == null) {pvs = mbd.getPropertyValues();}// 执行InstantiationAwareBeanPostProcessor的postProcessProperties()以及postProcessPropertyValues()方法回调// postProcessProperties(): 允许对填充前的属性进行处理(如对属性的验证)// postProcessPropertyValues(): 对属性值进行修改,通过基于原始的PropertyValues创建一个新的MutablePropertyValues实例,添加或删除特定的值。// 不过目前方法已经被标记为过期,在后续Spring版本中可能会被删除for (BeanPostProcessor bp : getBeanPostProcessors()) {if (bp instanceof InstantiationAwareBeanPostProcessor) {InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);if (pvsToUse == null) {if (filteredPds == null) {filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);}pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);if (pvsToUse == null) {return;}}pvs = pvsToUse;}}}

6:依赖检查

// 6、执行依赖检查,对应depend-on属性if (needsDepCheck) {if (filteredPds == null) {filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);}// 依赖检查,对应depend-on属性checkDependencies(beanName, mbd, filteredPds, pvs);}

spring默认情况下是不检查依赖的,如果要使用依赖检查需要手动的在配置文件中设置。
依赖检查有四种模式:simple,objects,all,none
image.png
AbstractAutowireCapableBeanFactory

protected void checkDependencies(String beanName, AbstractBeanDefinition mbd, PropertyDescriptor[] pds, @Nullable PropertyValues pvs)throws UnsatisfiedDependencyException {// 获取检查依赖模式int dependencyCheck = mbd.getDependencyCheck();//  循环判断for (PropertyDescriptor pd : pds) {if (pd.getWriteMethod() != null && (pvs == null || !pvs.contains(pd.getName()))) {boolean isSimple = BeanUtils.isSimpleProperty(pd.getPropertyType());boolean unsatisfied = (dependencyCheck == AbstractBeanDefinition.DEPENDENCY_CHECK_ALL) ||(isSimple && dependencyCheck == AbstractBeanDefinition.DEPENDENCY_CHECK_SIMPLE) ||(!isSimple && dependencyCheck == AbstractBeanDefinition.DEPENDENCY_CHECK_OBJECTS);if (unsatisfied) {throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, pd.getName(),"Set this property value or disable dependency checking for this bean.");}}}}

7:具体的属性填充

// 7、属性填充的具体过程,即将属性值赋值到beanWrapper中bean实例的具体属性中if (pvs != null) {// 开始填充属性值applyPropertyValues(beanName, mbd, bw, pvs);}
/*** Apply the given property values, resolving any runtime references* to other beans in this bean factory. Must use deep copy, so we* don't permanently modify this property.* <p>应用给定的属性值,解决任何在这个bean工厂运行时其他bean的引用。必须使用深拷贝,所以我们* 不会永久地修改这个属性</p>* @param beanName the bean name passed for better exception information*                 -- 传递bean名以获得更好的异常信息* @param mbd the merged bean definition*            -- 合并后的bean定义* @param bw the BeanWrapper wrapping the target object*           -- 包装目标对象的BeanWrapper* @param pvs the new property values*            -- 新得属性值*/protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {//如果pvs没有PropertyValueif (pvs.isEmpty()) {//直接结束方法return;}//如果有安全管理器 且 bw是BeanWrapperImpld恶实例if (System.getSecurityManager() != null && bw instanceof BeanWrapperImpl) {//设置bw的安全上下文为工厂的访问控制上下文((BeanWrapperImpl) bw).setSecurityContext(getAccessControlContext());}//MutablePropertyValues:PropertyValues接口的默认实现。允许对属性进行简单操作,并提供构造函数来支持从映射 进行深度复制和构造MutablePropertyValues mpvs = null;//原始属性值列表List<PropertyValue> original;//如果pvs是MutablePropertyValues实例if (pvs instanceof MutablePropertyValues) {//将pvs强转为MutablePropertyValue实例mpvs = (MutablePropertyValues) pvs;//isConverted:返回该holder是否只包含转换后的值(true),或者是否仍然需要转换这些值//如果mpvs只包含转换后的值if (mpvs.isConverted()) {// Shortcut: use the pre-converted values as-is.// 快捷方式:使用 pre-conveted初始值try {//使用mpvs批量设置bw包装的Bean对象属性bw.setPropertyValues(mpvs);//终止方法。return;}catch (BeansException ex) {//捕捉Bean异常,重新抛出Bean创佳异常:错误设置属性值。throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Error setting property values", ex);}}//获取mpvs的PropertyValue对象列表original = mpvs.getPropertyValueList();}else {//获取pvs的PropertyValue对象数组,并将其转换成列表original = Arrays.asList(pvs.getPropertyValues());}//获取工厂的自定义类型转换器TypeConverter converter = getCustomTypeConverter();//如果工厂中没有设置自定义类型转换器if (converter == null) {//使用bw作为转换器converter = bw;}//BeanDefinitionValueResolver:在bean工厂实现中使用Helper类,它将beanDefinition对象中包含的值解析为应用于 目标bean实例的实际值BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);// Create a deep copy, resolving any references for values.// 创建一个深拷贝,解析任何值引用List<PropertyValue> deepCopy = new ArrayList<>(original.size());//是否还需要解析标记boolean resolveNecessary = false;//遍历orgininalfor (PropertyValue pv : original) {//如果pv已经是转换后的值if (pv.isConverted()) {//将pv添加到deepCopy中deepCopy.add(pv);}else {//pv需要转换值//获取pv的属性名String propertyName = pv.getName();//获取pv的原始属性值Object originalValue = pv.getValue();//AutowiredPropertyMarker.INSTANCE:自动生成标记的规范实例if (originalValue == AutowiredPropertyMarker.INSTANCE) {//获取propertyName在bw中的setter方法Method writeMethod = bw.getPropertyDescriptor(propertyName).getWriteMethod();//如果setter方法为nullif (writeMethod == null) {//抛出非法参数异常:自动装配标记属性没有写方法。throw new IllegalArgumentException("Autowire marker for property without write method: " + pv);}//将writerMethod封装到DependencyDescriptor对象originalValue = new DependencyDescriptor(new MethodParameter(writeMethod, 0), true);}//交由valueResolver根据pv解析出originalValue所封装的对象Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);//默认转换后的值是刚解析出来的值Object convertedValue = resolvedValue;//可转换标记: propertyName是否bw中的可写属性 && prepertyName不是表示索引属性或嵌套属性(如果propertyName中有'.'||'['就认为是索引属性或嵌套属性)boolean convertible = bw.isWritableProperty(propertyName) &&!PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName);//如果可转换if (convertible) {//将resolvedValue转换为指定的目标属性对象convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter);}// Possibly store converted value in merged bean definition,// in order to avoid re-conversion for every created bean instance.// 可以将转换后的值存储合并后BeanDefinition中,以避免对每个创建的Bean实例进行重新转换//如果resolvedValue与originalValue是同一个对象if (resolvedValue == originalValue) {//如果可转换if (convertible) {//将convertedValue设置到pv中pv.setConvertedValue(convertedValue);}//将pv添加到deepCopy中deepCopy.add(pv);}//TypedStringValue:类型字符串的Holder,这个holder将只存储字符串值和目标类型。实际得转换将由Bean工厂执行//如果可转换 && originalValue是TypedStringValue的实例 && orginalValue不是标记为动态【即不是一个表达式】&&// 	convertedValue不是Collection对象 或 数组else if (convertible && originalValue instanceof TypedStringValue &&!((TypedStringValue) originalValue).isDynamic() &&!(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) {//将convertedValue设置到pv中pv.setConvertedValue(convertedValue);//将pv添加到deepCopy中deepCopy.add(pv);}else {//标记还需要解析resolveNecessary = true;//根据pv,convertedValue构建PropertyValue对象,并添加到deepCopy中deepCopy.add(new PropertyValue(pv, convertedValue));}}}//mpvs不为null && 已经不需要解析if (mpvs != null && !resolveNecessary) {//将此holder标记为只包含转换后的值mpvs.setConverted();}// Set our (possibly massaged) deep copy.// 设置我们的深层拷贝(可能时按摩过的)try {//按原样使用deepCopy构造一个新的MutablePropertyValues对象然后设置到bw中以对bw的属性值更新bw.setPropertyValues(new MutablePropertyValues(deepCopy));}catch (BeansException ex) {//捕捉更新属性值的Bean异常//重新抛出Bean创建异常:错误设置属性值throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Error setting property values", ex);}}

大体步骤:

  • 首先检查是否存在要应用的属性值,如果属性值为空,直接返回。
  • 如果有安全管理器且bwBeanWrapperImpl的实例,设置bw的安全上下文为工厂的访问控制上下文。
  • 创建MutablePropertyValues对象,并根据传入的属性值对象(pvs)初始化。
  • 进行属性值的解析和类型转换,确保属性值可以正确地应用到Bean实例中。
  • 最后,将转换后的属性值设置到bw包装的Bean对象中,更新Bean的属性值。

后面会出文章详细介绍的,到这我们就完成了属性填充

1.2.2 initializeBean方法

initializeBean()主要完成如执行aware接口、执行init-method方法、BeanPostProcessor后置增强等工作。
AbstractAutowireCapableBeanFactory

protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {// 注释 4.12 securityManage 是啥,不确定=-=if (System.getSecurityManager() != null) {AccessController.doPrivileged((PrivilegedAction<Object>) () -> {invokeAwareMethods(beanName, bean);return null;}, getAccessControlContext());}else {// 如果没有 securityManage,方法里面校验了 bean 的类型,需要引用 Aware 接口// 对特殊的 bean 处理:Aware/ BeanClassLoader / BeanFactoryAwareinvokeAwareMethods(beanName, bean);}Object wrappedBean = bean;if (mbd == null || !mbd.isSynthetic()) {// 熟悉么,后处理器又来了// 注释 7.3 bean 实例化阶段,调用已经注册好的 beanPostProcessor 的 postProcessBeforeInitialization 方法wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);}try {// 激活用户自定义的 init-method 方法invokeInitMethods(beanName, wrappedBean, mbd);}catch (Throwable ex) {throw new BeanCreationException((mbd != null ? mbd.getResourceDescription() : null),beanName, "Invocation of init method failed", ex);}if (mbd == null || !mbd.isSynthetic()) {// bean 实例化阶段,调用已经注册好的 beanPostProcessor 的 postProcessAfterInitialization 方法wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);}return wrappedBean;}

initializeBean()方法处理过程:
1、执行Aware方法,如BeanNameAware、BeanClassLoaderAware、BeanFactoryAware
2、执行BeanPostProcessor后置处理器的前置处理方法:postProcessBeforeInitialization(),允许对bean实例进行包装
3、执行初始化方法,包括InitializingBean的afterPropertiesSet()方法、自定义的初始化方法init-method
4、执行BeanPostProcessor后置处理器的后置处理方法:postProcessAfterInitialization(),允许对bean实例进行包装

执行Aware方法

AbstractAutowireCapableBeanFactory

// 注释 4.12 securityManage 是啥,不确定=-=if (System.getSecurityManager() != null) {AccessController.doPrivileged((PrivilegedAction<Object>) () -> {invokeAwareMethods(beanName, bean);return null;}, getAccessControlContext());}else {// 如果没有 securityManage,方法里面校验了 bean 的类型,需要引用 Aware 接口// 对特殊的 bean 处理:Aware/ BeanClassLoader / BeanFactoryAwareinvokeAwareMethods(beanName, bean);}
  • invokeAwareMethods():执行Aware方法,如BeanNameAware、BeanClassLoaderAware、BeanFactoryAware
// 实现Aware接口的bean在被初始化后,可以取得一些相对应的资源,如BeanFactory、ApplicationContext等,下面就是具体的赋值过程
private void invokeAwareMethods(String beanName, Object bean) {if (bean instanceof Aware) {// 1、如果bean实现了BeanNameAware接口,那么在bean内部可以获取到BeanName属性if (bean instanceof BeanNameAware) {((BeanNameAware) bean).setBeanName(beanName);}// 2、如果bean实现了BeanClassLoaderAware接口,那么在bean内部可以获取到BeanClassLoader对象if (bean instanceof BeanClassLoaderAware) {ClassLoader bcl = getBeanClassLoader();if (bcl != null) {((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);}}// 3、如果bean实现了BeanFactoryAware接口,那么在bean内部可以获取到BeanFactory工厂对象if (bean instanceof BeanFactoryAware) {((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);}}
}

执行BeanPostProcessor后置处理器的前置处理方法

这里需要看一下上一篇的Bean的后置处理

Object wrappedBean = bean;if (mbd == null || !mbd.isSynthetic()) {// 2、执行BeanPostProcessor后置处理器的前置处理方法:postProcessBeforeInitialization(),允许对bean实例进行包装wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);}
  • applyBeanPostProcessorsBeforeInitialization():执行BeanPostProcessor后置处理器的前置处理方法
	@Overridepublic Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)throws BeansException {Object result = existingBean;// 1、获取到当前工厂中注册的所有BeanPostProcessor后置处理器for (BeanPostProcessor processor : getBeanPostProcessors()) {// 2、执行每一个BeanPostProcessor的前置增强方法:postProcessBeforeInitialization()Object current = processor.postProcessBeforeInitialization(result, beanName);if (current == null) {// 3、如果postProcessBeforeInitialization()返回为空,则直接返回,将不会执行后续的BeanPostProcessor后置处理器的增强return result;}// 4、使用增强后的bean current,赋值给result,然后返回result = current;}return result;}

执行初始化方法

try {// 3、执行初始化方法,包括InitializingBean的afterPropertiesSet()方法、自定义的初始化方法init-methodinvokeInitMethods(beanName, wrappedBean, mbd);} catch (Throwable ex) {throw new BeanCreationException((mbd != null ? mbd.getResourceDescription() : null),beanName, "Invocation of init method failed", ex);}
  • invokeInitMethods():执行初始化方法,包括InitializingBean的afterPropertiesSet()方法、自定义的初始化方法init-method
protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd)throws Throwable {// 1、检查bean是否实现了InitializingBean接口,如果实现了,则需要执行InitializingBean接口的afterPropertiesSet()方法boolean isInitializingBean = (bean instanceof InitializingBean);if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {if (logger.isTraceEnabled()) {logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");}// 2、调用InitializingBean接口的afterPropertiesSet()方法if (System.getSecurityManager() != null) {try {AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {((InitializingBean) bean).afterPropertiesSet();return null;}, getAccessControlContext());} catch (PrivilegedActionException pae) {throw pae.getException();}} else {((InitializingBean) bean).afterPropertiesSet();}}// 3、调用用户自定义的初始化方法,比如init-method等if (mbd != null && bean.getClass() != NullBean.class) {String initMethodName = mbd.getInitMethodName();if (StringUtils.hasLength(initMethodName) &&!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&!mbd.isExternallyManagedInitMethod(initMethodName)) {// 执行用户自定义的初始化方法invokeCustomInitMethod(beanName, bean, mbd);}}
}

执行BeanPostProcessor后置处理器的后置处理方法:postProcessAfterInitialization(),允许对bean实例进行包装

if (mbd == null || !mbd.isSynthetic()) {// 4、执行BeanPostProcessor后置处理器的后置处理方法:postProcessAfterInitialization(),允许对bean实例进行包装wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);}
  • applyBeanPostProcessorsAfterInitialization():执行BeanPostProcessor后置处理器的后置处理方法:postProcessAfterInitialization(),允许对bean实例进行包装
	public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)throws BeansException {Object result = existingBean;// 1、获取到工厂中注册的所有BeanPostProcessor后置增强器for (BeanPostProcessor processor : getBeanPostProcessors()) {// 2、执行BeanPostProcessor的后置增强方法postProcessAfterInitialization()Object current = processor.postProcessAfterInitialization(result, beanName);if (current == null) {// 3、如果postProcessAfterInitialization()返回为空,则直接返回,将不会执行后续的BeanPostProcessor后置处理器的增强return result;}// 4、使用增强后的bean current,赋值给result,然后返回result = current;}return result;}

1.3 根据 scope 注册 bean

注册DisposableBean的实现,在注销时执行来源于DestructionAwareBeanPostProcessors、实现的DisposableBean的destroy方法还有自己配置的destroy-method的处理。

// Register bean as disposable.// 根据 scope 注册 beantry {registerDisposableBeanIfNecessary(beanName, bean, mbd);}catch (BeanDefinitionValidationException ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);}

AbstractBeanFactory

	protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) {AccessControlContext acc = (System.getSecurityManager() != null ? getAccessControlContext() : null);// 如果bean的作用域不是prototype,且bean需要在关闭时进行销毁if (!mbd.isPrototype() && requiresDestruction(bean, mbd)) {// 如果bean的作用域是singleton,则会注册用于销毁的bean到disposableBeans缓存,执行给定bean的所有销毁工作if (mbd.isSingleton()) {// Register a DisposableBean implementation that performs all destruction// work for the given bean: DestructionAwareBeanPostProcessors,// DisposableBean interface, custom destroy method.registerDisposableBean(beanName, new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));} else {// 如果bean的作用域不是prototype、也不是singleton,而是其他作自定义用域的话,则注册一个回调,以在销毁作用域内的指定对象时执行// A bean with a custom scope...Scope scope = this.scopes.get(mbd.getScope());if (scope == null) {throw new IllegalStateException("No Scope registered for scope name '" + mbd.getScope() + "'");}scope.registerDestructionCallback(beanName, new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));}}}public void registerDisposableBean(String beanName, DisposableBean bean) {// 注册用于销毁的bean到disposableBeans缓存synchronized (this.disposableBeans) {// private final Map<String, Object> disposableBeans = new LinkedHashMap<>();this.disposableBeans.put(beanName, bean);}
}

我们后面来详细分析,到这我们就完成了Bean的整个流程,后面我们正对各个模块来进行分析,前面的分析这是一个整体流程的概述,相当于下面的代码部分,这只是正对下面的一个流程的分析

package org.springframework.shu;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;
/*** @description: 测试Bean* @author: shu* @createDate: 2023/4/3 14:56* @version: 1.0*/
public class AppTest {@Testpublic void MyTestBeanTest() {BeanFactory bf = new XmlBeanFactory( new ClassPathResource("spring-config.xml"));MyTestBean myTestBean = (MyTestBean) bf.getBean("myTestBean");System.out.println(myTestBean.getName());}
}

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

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

相关文章

MySQL数据库基本操作

目录 一、数据库中常用的数据类型 二、常用命令与操作 1.DDL数据库定义语言 1、登录用户的数据库 2、查看当前服务器中的数据库 3、切换/进入数据库 并 查看数据库中包含的表 4、查看数据库中表的结构 5、创建数据库 7、展示创建数据表时的结构 8、创建表&#xff0c…

Linux 三剑客

grep grep主打的就是查找功能 &#xff0c;它能够在一个或者多个文件中搜索某一特定的字符模式。 grep的语法 grep [选项] 模式 文件名 先说选项&#xff1a; 1.选项 要么是正则要么是字符串 -c 列出共出现多少次 -i 忽略大小写 -n 在前面列出行号 -v …

阿里云centos9stream安装宝塔+vscode(code-server)集成云端开发环境

一、 安装宝塔面板 官网 https://www.bt.cn/new/download.htm 题外话&#xff1a;虽然感觉现在宝塔没以前好用了&#xff0c;而且有centos7、8 mysql编译导致OOM服务器挂掉无法ssh登录的情况&#xff0c;但他还是远程管理服务器的好选择&#xff0c;提示宝塔只支持最新的centos…

常见矿石材质鉴定VR实训模拟操作平台提高学员的学习效果和实践能力

随着“元宇宙”概念的不断发展&#xff0c;在矿山领域中&#xff0c;长期存在传统培训内容不够丰富、教学方式单一、资源消耗大等缺点&#xff0c;无法适应当前矿山企业发展需求的长期难题。元宇宙企业借助VR虚拟现实、web3d开发和计算机技术构建的一个虚拟世界&#xff0c;为用…

SpringBoot虚拟路径映射

要求&#xff1a;访问&#xff1a;127.0.0.1/image/下的文件时&#xff0c;自动映射到真实路径&#xff1a;D:Files\。 virtualFileDepositPath: /image/** realityFileDepositPath: C:\Users\xin\Desktop\imgCreate\Files\ import org.springframework.beans.factory.annota…

编写c语言程序调用openssl编译出的动态链接库

文章目录 一、编译生成链接库二、示例一&#xff1a;调用RAND_bytes函数三、示例二&#xff1a;调用SHA256 一、编译生成链接库 下载安装openssl并编译生成链接库的过程在我的另一篇文章中已经详细说明了&#xff1a;Ubuntu中安装OpenSSL 此外&#xff0c;我们还需要提前了解…

微服务之Nacos

1 版本说明 官网地址&#xff1a; https://github.com/alibaba/spring-cloud-alibaba/wiki/%E7%89%88%E6%9C%AC%E8%AF%B4%E6%98%8E 1.1 2021.x 分支 适配 SpringBoot 2.4, Spring Cloud 2021.x 版本及以上的Spring Cloud Alibaba 版本如下表&#xff08;最新版本用*标记&am…

RHCE——十三、Shell自动化运维编程基础

Shell 一、为什么学习和使用Shell编程二、Shell是什么1、shell起源2、查看当前系统支持的shell3、查看当前系统默认shell4、Shell 概念 三、Shell 程序设计语言1、Shell 也是一种脚本语言2、用途 四、如何学好shell1、熟练掌握shell编程基础知识2、建议 五、Shell脚本的基本元素…

docker-compose安装opengauss数据库

文章目录 1. docker-compose.yaml2. 部署3. 卸载4. 连接 1. docker-compose.yaml mkdir -p /root/i/docker-compose/opengauss && cd /root/i/docker-compose/opengausscat <<EOF> /root/i/docker-compose/opengauss/docker-compose.yaml version: 3 service…

计算机竞赛 基于机器视觉的停车位识别检测

简介 你是不是经常在停车场周围转来转去寻找停车位。如果你的车辆能准确地告诉你最近的停车位在哪里&#xff0c;那是不是很爽&#xff1f;事实证明&#xff0c;基于深度学习和OpenCV解决这个问题相对容易&#xff0c;只需获取停车场的实时视频即可。 该项目较为新颖&#xf…

MongoDB实验——在MongoDB集合中查找文档

在MongoDB集合中查找文档 一、实验目的二、实验原理三、实验步骤1.启动MongoDB数据库、启动MongoDB Shell客户端2.数据准备-->person.json3.指定返回的键4 .包含或不包含 i n 或 in 或 in或nin、$elemMatch&#xff08;匹配数组&#xff09;5.OR 查询 $or6.Null、$exists7.…

【JavaScript精通之道】掌握数据遍历:解锁现代化遍历方法,提升开发效率!

​ &#x1f3ac; 岸边的风&#xff1a;个人主页 &#x1f525; 个人专栏 :《 VUE 》 《 javaScript 》 ⛺️ 生活的理想&#xff0c;就是为了理想的生活 ! ​ 目录 &#x1f4da; 前言 &#x1f4d8; 1. reduce方法 &#x1f4d8; 2. forEach方法 &#x1f4d8; 3. map方法…

浏览器连不上 Flink WebUI 8081 端口

安装 flink-1.17.0 后&#xff0c;start-cluster.sh 启动&#xff0c;发现浏览器连不上 Flink WebUI 的8081端口。 问题排查&#xff1a; command R&#xff0c;输入cmd&#xff0c;检查宿主机能否ping通虚拟机&#xff0c;发现能ping通。 检查是否有flink以外的任务占用8081…

一体化数据安全平台 uDSP 获“金鼎奖”优秀金融科技解决方案奖

近日&#xff0c;2023 年中国国际金融展“金鼎奖”评选结果揭晓&#xff0c;原点安全打造的“一体化数据安全平台 uDSP”产品获评“金鼎奖”优秀金融科技解决方案奖。该产品目前已广泛应用于银行业、保险企业、证券、医疗、互联网、政务、在线教育等诸多领域。此次获奖再次印证…

如何避免重复消费消息

博主介绍&#xff1a;✌全网粉丝3W&#xff0c;全栈开发工程师&#xff0c;从事多年软件开发&#xff0c;在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建与毕业项目实战&#xff0c;博主也曾写过优秀论文&#xff0c;查重率极低&#xff0c;在这方面有丰富的经验…

这个 AI 机器人会怼人,它是怎么做到的?

近期&#xff0c;机器人“Ameca”接入了 Stable Diffusion&#xff0c;它一边与旁边的人类工程师谈笑风生&#xff0c;一边熟练地用马克笔在白板上画出一只简笔的猫&#xff0c;最后还在白板右下角签名。 当 Ameca 询问工程师是否对它的作品是否满意时&#xff0c;工程师回答“…

光流法相关论文-LK光流法,HS光流法,Farneback光流法,FlowNet: 端到端的深度光流估计, RAFT: 结构化的光流估计

目录 光流法 1. Lucas-Kanade光流法&#xff08;稀疏光流法&#xff09;&#xff1a; 2. Horn-Schunck光流法&#xff08;稠密光流法&#xff09;&#xff1a; 3. Farneback光流法&#xff1a; 4 FlowNet: 端到端的深度光流估计&#xff1a; 5. RAFT: 结构化的光流…

基于空洞卷积DCNN与长短期时间记忆模型LSTM的dcnn-lstm的回归预测模型

周末的时候有时间鼓捣的一个小实践&#xff0c;主要就是做的多因子回归预测的任务&#xff0c;关于时序数据建模和回归预测建模我的专栏和系列博文里面已经有了非常详细的介绍了&#xff0c;这里就不再多加赘述了&#xff0c;这里主要是一个模型融合的实践&#xff0c;这里的数…

[论文笔记]DSSM

引言 这是DSSM论文的阅读笔记,后续会有一篇文章来复现它并在中文数据集上验证效果。 本文的标题翻译过来就是利用点击数据学习网页搜索中深层结构化语义模型,这篇论文被归类为信息检索,但也可以用来做文本匹配。 这是一篇经典的工作,在DSSM之前,通常使用传统机器学习的…