【Spring专题】Spring之Bean的生命周期源码解析——阶段二(一)(IOC之实例化)

news2024/12/28 19:11:49

目录

  • 前言
    • 阅读准备
    • 阅读指引
    • 阅读建议
  • 课程内容
    • 一、SpringIOC之实例化
      • 1.1 简单回顾
      • 1.2 概念回顾
      • 1.3 核心方法讲解
    • 二、方法讲解
      • 2.1 AbstractBeanFactory#getMergedLocalBeanDefinition:合并BeanDefinition
      • 2.2 AbstractAutowireCapableBeanFactory#createBean:创建Bean
      • 2.3 AbstractAutowireCapableBeanFactory#resolveBeanClass:加载类
      • *2.4 AbstractAutowireCapableBeanFactory#resolveBeforeInstantiation:【实例化前】入口
      • 2.5 AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInstantiation:【实例化前】真正干活的地方
      • 2.6 AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization:第一次可能调用【初始化后】
      • 2.7 AbstractAutowireCapableBeanFactory#doCreateBean:【实例化】入口(包括后续的实例化过程)
      • *2.8 AbstractAutowireCapableBeanFactory#createBeanInstance:实例化
        • 2.8.1 Supplier创建对象
        • 2.8.2 工厂方法创建对象
        • 2.8.3 构造方法创建对象
      • 2.9 AbstractAutowireCapableBeanFactory#autowireConstructor:推断构造方法
      • 2.10 AbstractAutowireCapableBeanFactory#applyMergedBeanDefinitionPostProcessors:BeanDefinition后置处理
      • 2.11 AbstractAutowireCapableBeanFactory#populateBean:属性注入(包含:实例化后)
      • 方法总结后
    • 三、实例化逻辑流程图
  • 学习总结

前言

阅读准备

由于Spring源码分析是一个前后联系比较强的过程,而且这边分析,也是按照代码顺序讲解的,所以不了解前置知识的情况下,大概率没办法看懂当前的内容。所以,特别推荐看看我前面的文章(自上而下次序):

  • Spring底层核心原理解析——引导篇【学习难度:★★☆☆☆
  • 手写简易Spring容器过程分析——引导篇【学习难度:★★☆☆☆
  • Spring之底层架构核心概念解析【学习难度:★★★☆☆,重要程度:★★★★★
  • Bean的生命周期流程图【学习难度:☆☆☆☆☆,重要程度:★★★★★
  • Spring之Bean的生命周期源码解析——阶段一(扫描生成BeanDefinition)【学习难度:★★☆☆☆,重要程度:★★★☆☆

(PS:特别是《Bean的生命周期流程图》,帮大家【开天眼】,先了解下流程。毕竟【通过业务了解代码,远比通过代码了解业务简单的多】!!!!)
(PS:特别是《Bean的生命周期流程图》,帮大家【开天眼】,先了解下流程。毕竟【通过业务了解代码,远比通过代码了解业务简单的多】!!!!)
(PS:特别是《Bean的生命周期流程图》,帮大家【开天眼】,先了解下流程。毕竟【通过业务了解代码,远比通过代码了解业务简单的多】!!!!)

阅读指引

我们在上一节课已经说到过了,本次Spring源码剖析的总入口是new AnnotationConfigApplicationContext("org.tuling.spring");,这里就不再重复解释了。本节课要说的内容,是SpringIOC的实例化,我们这里直接给到入口吧,调用链如下:(调用链比较深,不要纠结细枝末节

  1. AbstractApplicationContext#refresh:刷新方法,不用在意
  2. AbstractApplicationContext#finishBeanFactoryInitialization:在这里实例化所有剩余的(非lazy-init)单例
  3. DefaultListableBeanFactory#preInstantiateSingletons:在这里实例化所有剩余的(非lazy-init)单例(上面的方法,核心干活的方法就是这里)
  4. DefaultListableBeanFactory#getBean:获取Bean的方法
  5. AbstractBeanFactory#doGetBean:返回指定bean的一个实例,它可以是共享的,也可以是独立的
  6. 上面这个AbstractBeanFactory#doGetBean里面的一段局部代码写的回调方法,如下:
	// 如果是单例创建bean实例
	if (mbd.isSingleton()) {
		sharedInstance = getSingleton(beanName, () -> {
			try {
				return createBean(beanName, mbd, args);
			}
			catch (BeansException ex) {
				// Explicitly remove instance from singleton cache: It might have been put there
				// eagerly by the creation process, to allow for circular reference resolution.
				// Also remove any beans that received a temporary reference to the bean.
				destroySingleton(beanName);
				throw ex;
			}
		});
		beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
	}
  1. AbstractAutowireCapableBeanFactory#createBean:这个类的中心方法:创建一个bean实例,填充bean实例,应用后处理器,等等。

如上面的调用链所示,最后一个方法,才是我们本次要研究的核心方法。而且通过注释,我想大家也看到了,这个方法不单单干了实例化的工作,还有属性填充、各种后置处理器等。(PS:哈哈,同学们,我知道这个【实例化】调用链挺深的,但是大家不要烦恼,只要切记【不要纠结那些细枝末节】那一切都OK,我们老老实实地跟着主线来研究就好,毕竟这些才是核心)

阅读建议

  1. 看源码,切记纠结细枝末节,不然很容易陷进去。正常来说,看主要流程就好了
  2. 遇到不懂的,多看看类注释或者方法注释。Spring这种优秀源码,注释真的非常到位
  3. 如果你是idea用户,多用F11的书签功能。
    • Ctrl + F11 选中文件 / 文件夹,使用助记符设定 / 取消书签 (必备)
    • Shift + F11 弹出书签显示层 (必备)
    • Ctrl +1,2,3…9 定位到对应数值的书签位置 (必备)

课程内容

一、SpringIOC之实例化

这里说的【实例化】,是指单例的实例化,原型prototype不包含在内

1.1 简单回顾

大家知道,实例化的过程是怎样的吗?哈,我知道大部分的同学可能都不会知道。所以呢,我希望大家真的要有去看过《 Bean的声明周期流程图》,因为,通过【代码去理解业务】,远远比【通过业务理解代码】难得多!直接看个图吧,起码咱得知道【实例化到底干了什么,有哪些步骤】,我们才能更好的去研究。
在这里插入图片描述

如上图所示,实例化包含了:合并BeanDefinition、加载类、实例化之前、推断构造方法、实例化、BeanDefinition的后置处理、实例化后等,这些关键步骤。这就是我们本篇文章研究的核心!!

1.2 概念回顾

在这个【实例化】过程中,涉及到了一些Spring底层设计的概念,我在上一个笔记里面有大概介绍过Spring底层概念的一些讲解,不记得的同学记得回去翻一翻。
主要涉及的概念有:

  • BeanDefinition(设计图纸):BeanDefinition表示Bean定义,BeanDefinition中存在很多属性用来描述一个Bean的特征
  • BeanPostProcessor(Spring重要的拓展点):Bean的后置处理器,对Bean做拓展操作。我们前面说过,BeanPostProcessor提供了【初始化前/后】两个拓展方法。但是这里,Spring内部对这个接口做了很多拓展,新增了一些继承自BeanPostProcessor的子类或者子接口。在实例化阶段,主要用到的接口如下:
    • InstantiationAwareBeanPostProcessor,直译过来就是:能感知实例化的Bean后置处理器。而这个继承自BeanPostProcessor,显然也具备这【初始化前/后】两个拓展方法。另外,通过InstantiationAwareBeanPostProcessor的名字大家也能猜到了,它肯定是具有对【实例化】阶段拓展的能力的。接口定义在后面。
    • SmartInstantiationAwareBeanPostProcessor:直译过来就是:智能的,能感知实例化的Bean后置处理器。在这个接口中,拓展了InstantiationAwareBeanPostProcessor接口,新增了几个函数,其中就包括了推断构造的实现。另外,这是一个框架内部使用接口。接口定义在后面。
    • MergedBeanDefinitionPostProcessor:直译过来就是:合并BeanDefinition的后置处理器。运行时用于合并bean定义的后处理器回调接口。接口定义在后面。

InstantiationAwareBeanPostProcessor接口定义如下:

/**
 * BeanPostProcessor的子接口,用于添加实例化前回调,以及实例化后但显式属性设置或自动生成之前的回调。
 * 通常用于抑制特定目标bean的默认实例化,例如创建具有特殊TargetSources的代理(池化目标、惰性初始化目标等),或者实现额外的注入策略,如字段注入。
 * 注:此接口为专用接口,主要供框架内部使用。建议尽可能实现普通的BeanPostProcessor接口。
 * 自:
 * 1.2
 * 参见:
 * org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.setCustomTargetSourceCreators, org.springframework.aop.framework.autoproxy.target.LazyInitTargetSourceCreator
 * 作者:
 * 于尔根·霍勒,罗德·约翰逊
 */
public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {

	/**
	 * 在目标bean实例化之前应用这个BeanPostProcessor。返回的bean对象可能是要使用的代理而不是目标bean,从而有效地抑制目标bean的默认实例化。
	 * 如果此方法返回一个非空对象,则bean创建过程将会中断。应用的唯一进一步处理是来自配置的BeanPostProcessors的postProcessAfterInitialization回调。
	 * 这个回调将应用于带有bean类的bean定义,以及工厂方法定义,在这种情况下,返回的bean类型将在这里传递。
	 * 后置处理器可以实现扩展的SmartInstantiationAwareBeanPostProcessor接口,以便预测它们将在这里返回的bean对象的类型。
	 * 默认实现返回null。
	 * 参数:
	 * beanClass——要实例化的bean的类
	 * beanName—bean的名称
	 * 返回:
	 * 要公开的bean对象,而不是目标bean的默认实例,或者为空,继续进行默认实例化
	 * 抛出:
	 * BeansException -在错误的情况下
	 * 参见:
	 * postProcessAfterInstantiation, org.springframework.beans.factory.support.AbstractBeanDefinition.getBeanClass(), org.springframework.beans.factory.support.AbstractBeanDefinition.getFactoryMethodName()
	 */
	@Nullable
	default Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
		return null;
	}

	/**
	 * 在bean通过构造函数或工厂方法实例化之后,但在Spring属性填充(来自显式属性或自动装配)发生之前执行操作。
	 * 这是在Spring自动装配开始之前对给定bean实例执行自定义字段注入的理想回调。
	 * 默认实现返回true。
	 * 参数:
	 * Bean—已创建的Bean实例,其属性尚未设置
	 * beanName—bean的名称
	 * 返回:
	 * 如果应该在bean上设置属性,则为True;如果应该跳过属性人口,则为False。正常的实现应该返回true。返回false还将阻止在此bean实例上调用任何后续的InstantiationAwareBeanPostProcessor实例。
	 * 抛出:
	 * BeansException -在错误的情况下
	 * 参见:
	 * postProcessBeforeInstantiation
	 */
	default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
		return true;
	}

	/**
	 * 在工厂将给定的属性值应用到给定的bean之前,对它们进行后处理,不需要任何属性描述符。
	 * 如果实现提供自定义postProcessPropertyValues实现,则应该返回null(默认值),否则则返回pvs。在该接口的未来版本中(删除了postProcessPropertyValues),默认实现将直接返回给定的pv。
	 * 参数:
	 * PVS—工厂将要应用的属性值(永远不会为空)
	 * bean——已创建的bean实例,但其属性尚未设置
	 * beanName—bean的名称
	 * 返回:
	 * 应用于给定bean的实际属性值(可以是传入的PropertyValues实例),或者null,它继续处理现有属性,但特别地继续调用postProcessPropertyValues(需要为当前bean类初始化PropertyDescriptors)。
	 * 抛出:
	 * BeansException -在错误的情况下
	 * 自:
	 * 5.1
	 * 参见:
	 * postProcessPropertyValues
	 */
	@Nullable
	default PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName)
			throws BeansException {

		return null;
	}

	/**
	 * 在工厂将给定属性值应用到给定bean之前,对它们进行后处理。允许检查是否满足所有依赖项,例如基于bean属性设置器上的“Required”注释。
	 * 还允许替换要应用的属性值,通常通过基于原始PropertyValues创建新的MutablePropertyValues实例,添加或删除特定值。
	 * 默认实现按原样返回给定的pv。
	 * 弃用
	 * 从5.1开始,支持postProcessProperties(PropertyValues, Object, String)
	 * 参数:
	 * PVS—工厂将要应用的属性值(永远不会为空)
	 * PDS——目标bean的相关属性描述符(忽略了依赖类型——工厂专门处理的依赖类型——已经过滤掉了)
	 * bean——已创建的bean实例,但其属性尚未设置
	 * beanName—bean的名称
	 * 返回:
	 * 应用于给定bean的实际属性值(可以是传入的PropertyValues实例),或者为null以跳过属性填充
	 * 抛出:
	 * BeansException -在错误的情况下
	 * 参见:
	 * postProcessProperties, org.springframework.beans.MutablePropertyValues
	 */
	@Deprecated
	@Nullable
	default PropertyValues postProcessPropertyValues(
			PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {

		return pvs;
	}
}

SmartInstantiationAwareBeanPostProcessor接口定义如下:

/**
 *  扩展了InstantiationAwareBeanPostProcessor接口,添加了一个回调函数,用于预测被处理bean的最终类型。
 * 注:此接口为专用接口,主要供框架内部使用。一般来说,应用程序提供的后处理器应该简单地实现普通的BeanPostProcessor接口,或者从InstantiationAwareBeanPostProcessorAdapter类派生。即使在点发布版本中,也可能向该接口添加新方法。
 * 自:
 * 2.0.3
 * 参见:
 * InstantiationAwareBeanPostProcessorAdapter
 * 作者:
 * Juergen hoel
 */
public interface SmartInstantiationAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessor {

	/**
	 * 预测这个处理器的postProcessBeforeInstantiation回调最终返回的bean的类型。
	 * 默认实现返回null。
	 * 参数:
	 * beanClass—bean的原始类beanName—bean的名称
	 * 返回:
	 * bean的类型,如果不可预测,则为空
	 * 抛出:
	 * BeansException -在错误的情况下
	 */
	@Nullable
	default Class<?> predictBeanType(Class<?> beanClass, String beanName) throws BeansException {
		return null;
	}

	/**
	 * 确定要为给定bean使用的候选构造函数。
	 * 默认实现返回null。
	 * 参数:
	 * beanClass—bean的原始类(不为空)beanName—bean的名称
	 * 返回:
	 * 候选构造函数,如果未指定,则为空
	 * 抛出:
	 * BeansException -在错误的情况下
	 */
	@Nullable
	default Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName)
			throws BeansException {

		return null;
	}

	/**
	 * 获取对指定bean的早期访问的引用,通常是为了解析循环引用。
	 * 这个回调让后处理器有机会尽早公开包装器——也就是说,在目标bean实例完全初始化之前。暴露的对象应该等同于postProcessBeforeInitialization / postProcessAfterInitialization所暴露的对象。请注意,此方法返回的对象将用作bean引用,除非后处理器返回与所述后处理回调不同的包装器。换句话说:那些处理后回调可能最终公开相同的引用,或者返回那些后续回调的原始bean实例(如果受影响的bean的包装器已经为对该方法的调用构建了,那么默认情况下它将作为最终bean引用公开)。
	 * 默认实现按原样返回给定的bean。
	 * 参数:
	 * bean—原始bean实例beanName—bean的名称
	 * 返回:
	 * 要作为bean引用公开的对象(通常将传入的bean实例作为默认值)
	 * 抛出:
	 * BeansException -在错误的情况下
	 */
	default Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
		return bean;
	}
}

MergedBeanDefinitionPostProcessor接口定义如下:

/**
 * 运行时用于合并bean定义的后处理器回调接口。BeanPostProcessor实现可以实现这个子接口,以便对合并的bean定义(原始bean定义的处理副本)进行后处理,Spring BeanFactory使用合并的bean定义来创建bean实例。
 * 例如,postProcessMergedBeanDefinition方法可以对bean定义进行内省,以便在对bean的实际实例进行后处理之前准备一些缓存的元数据。也允许修改bean定义,但只允许修改用于并发修改的定义属性。本质上,这只适用于在RootBeanDefinition本身上定义的操作,而不适用于其基类的属性。
 * 自:
 * 2.5
 * 参见:
 * org.springframework.beans.factory.config.ConfigurableBeanFactory.getMergedBeanDefinition
 * 作者:
 * Juergen hoel
 */
public interface MergedBeanDefinitionPostProcessor extends BeanPostProcessor {

	/**
	 * 对指定bean的给定合并bean定义进行后处理。
	 * 参数:
	 * beanDefinition—为bean合并的bean定义beanType—托管bean实例的实际类型beanName—bean的名称
	 * 参见:
	 * AbstractAutowireCapableBeanFactory.applyMergedBeanDefinitionPostProcessors
	 */
	void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName);

	/**
	 * 通知指定名称的bean定义已被重置,并且此后处理器应清除受影响bean的所有元数据。
	 * 默认实现为空。
	 * 参数:
	 * beanName—bean的名称
	 * 自:
	 * 5.1
	 * 参见:
	 * DefaultListableBeanFactory.resetBeanDefinition
	 */
	default void resetBeanDefinition(String beanName) {
	}
}

这里还是有一点想要提醒各位的,BeanPostProcessor是被Spring定义为【钩子】的,而钩子,很多时候都是为了改变系统原有行为的。这种改变,通常体现在:对Bean生命周期的影响,或者某个生命周期完成对象的改变等等。(这么说有点晦涩难懂,通俗点讲就是:Bean可能不会经过完整生命周期,比如【实例化前】之后,直接就跳到【初始化后】了,没有经过原本定义的【实例化】、【实例化后】、【其他后置处理】等;或者,原本初始化动作是Spring帮我门完成的,但是由于我们自己介入了,Spring就不帮我们初始化了,而是按照程序员意愿)

文章链接:
《【Spring专题】Spring之底层架构核心概念解析》

1.3 核心方法讲解

整个IOC实例化的主干过程,主要涉及了【2个类,11个核心方法】。下面,我们将会按照调用次序,依次讲解各个方法。

二、方法讲解

我们在上面说到过,这里的实例化过程包含了:合并BeanDefinition、加载类、实例化之前、推断构造方法、实例化、BeanDefinition的后置处理、实例化后等关键步骤。所以,在整个调用链上,基本上就是干了这些事情。
我们前面说过,本次的实例化代码入口如下:

	// 如果是单例创建bean实例
	if (mbd.isSingleton()) {
		sharedInstance = getSingleton(beanName, () -> {
			try {
				return createBean(beanName, mbd, args);
			}
			catch (BeansException ex) {
				// Explicitly remove instance from singleton cache: It might have been put there
				// eagerly by the creation process, to allow for circular reference resolution.
				// Also remove any beans that received a temporary reference to the bean.
				destroySingleton(beanName);
				throw ex;
			}
		});
		beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
	}

2.1 AbstractBeanFactory#getMergedLocalBeanDefinition:合并BeanDefinition

方法调用链:AbstractBeanFactory#doGetBean里面调用的
全路径:org.springframework.beans.factory.support.AbstractBeanFactory#getMergedLocalBeanDefinition
方法注释:返回合并的RootBeanDefinition,如果指定的bean对应于子bean定义,则遍历父bean定义。

我们在上节课最后的地方提到过这个,这边就不重复讲了,但是,他是算在实例化过程里面的,嘻嘻

2.2 AbstractAutowireCapableBeanFactory#createBean:创建Bean

方法调用链:AbstractBeanFactory#doGetBean里面调用的
全路径:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean
方法注释:这个类的中心方法:创建一个bean实例,填充bean实例,应用后处理器,等等。

源码如下:

	@Override
	protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
			throws BeanCreationException {

		if (logger.isTraceEnabled()) {
			logger.trace("Creating instance of bean '" + beanName + "'");
		}
		RootBeanDefinition mbdToUse = mbd;

		// 步骤一:加载类
		Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
		if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
			mbdToUse = new RootBeanDefinition(mbd);
			mbdToUse.setBeanClass(resolvedClass);
		}

		// 不用管这个
		try {
			mbdToUse.prepareMethodOverrides();
		}
		catch (BeanDefinitionValidationException ex) {
			throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
					beanName, "Validation of method overrides failed", ex);
		}

		try {
			// 步骤二:实例化前
			Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
			if (bean != null) {
				return bean;
			}
		}
		catch (Throwable ex) {
			throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
					"BeanPostProcessor before instantiation of bean failed", ex);
		}

		try {
			// 步骤三:创建Bean
			Object beanInstance = doCreateBean(beanName, mbdToUse, args);
			if (logger.isTraceEnabled()) {
				logger.trace("Finished creating instance of bean '" + beanName + "'");
			}
			return beanInstance;
		}
		catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
			// A previously detected exception with proper bean creation context already,
			// or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.
			throw ex;
		}
		catch (Throwable ex) {
			throw new BeanCreationException(
					mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
		}
	}

方法解读:上面代码老长一段,trt-catch占了一半,啊哈哈。 这里面的步骤就三个,下面也会讲到。

  1. resolveBeanClass:加载类
  2. resolveBeforeInstantiation:实例化前
  3. doCreateBean:真正创建Bean的地方

2.3 AbstractAutowireCapableBeanFactory#resolveBeanClass:加载类

PS:不算很重要,知道有这个步骤就好

方法调用链:由2.2的createBean调用过来
全路径:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#resolveBeanClass
方法注释:这个类的中心方法:创建一个bean实例,填充bean实例,应用后处理器,等等。

源码如下:

protected Class<?> resolveBeanClass(RootBeanDefinition mbd, String beanName, Class<?>... typesToMatch)
		throws CannotLoadBeanClassException {
	if (mbd.hasBeanClass()) {
		return mbd.getBeanClass();
	}
	if (System.getSecurityManager() != null) {
		return AccessController.doPrivileged((PrivilegedExceptionAction<Class<?>>)
				() -> doResolveBeanClass(mbd, typesToMatch), getAccessControlContext());
	}
	else {
		return doResolveBeanClass(mbd, typesToMatch);
	}
}

方法解读:这个代码外层挺简单的,也许大家对比System.getSecurityManager() != null这个比较难理解而已。这是Spring内部的一个安全管理器,很多时候都是不开启的。后面也会出现大量这种代码,反正遇到这个就直接看else的逻辑就好了。至于里层的doResolveBeanClass源码如下:

    private Class<?> doResolveBeanClass(RootBeanDefinition mbd, Class<?>... typesToMatch)
            throws ClassNotFoundException {

        // 步骤一:获取默认的类加载器
        ClassLoader beanClassLoader = getBeanClassLoader();
        ClassLoader dynamicLoader = beanClassLoader;
        boolean freshResolve = false;

        // 步骤二:在我们这个调用链上不会走这里,因为typesToMatch为null
        if (!ObjectUtils.isEmpty(typesToMatch)) {
            ClassLoader tempClassLoader = getTempClassLoader();
            if (tempClassLoader != null) {
                dynamicLoader = tempClassLoader;
                freshResolve = true;
                if (tempClassLoader instanceof DecoratingClassLoader) {
                    DecoratingClassLoader dcl = (DecoratingClassLoader) tempClassLoader;
                    for (Class<?> typeToMatch : typesToMatch) {
                        dcl.excludeClass(typeToMatch.getName());
                    }
                }
            }
        }

        // 步骤三
        String className = mbd.getBeanClassName();
        if (className != null) {

            // 步骤3.1:这里也不用怎么看,这是Spring表达式解析的东西。Spring表达式这个东西我们用的很少(类似EL表达式,这样来理解)
            Object evaluated = evaluateBeanDefinitionString(className, mbd);
            if (!className.equals(evaluated)) {
                if (evaluated instanceof Class) {
                    return (Class<?>) evaluated;
                }
                else if (evaluated instanceof String) {
                    className = (String) evaluated;
                    freshResolve = true;
                }
                else {
                    throw new IllegalStateException("Invalid class name expression result: " + evaluated);
                }
            }
            if (freshResolve) {
                if (dynamicLoader != null) {
                    try {

                        // 步骤3.2 加载类
                        return dynamicLoader.loadClass(className);
                    }
                    catch (ClassNotFoundException ex) {
                        if (logger.isTraceEnabled()) {
                            logger.trace("Could not load class [" + className + "] from " + dynamicLoader + ": " + ex);
                        }
                    }
                }
                return ClassUtils.forName(className, dynamicLoader);
            }
        }

        // 步骤四:正常来说走的是这里。使用默认的类加载器加载类
        return mbd.resolveBeanClass(beanClassLoader);
    }

方法解读:在这里,大体分为4个步骤。步骤一就是获取类加载器,往里追踪会发现,实际上调用的是ClassUtils.getDefaultClassLoader()方法。里面的代码挺简单的,获取原则如下:(需要一点JVM底子才懂,不了解也无所谓

  1. 优先返回当前线程中的ClassLoader
  2. 线程中类加载器为null的情况下,返回ClassUtils类的类加载器
  3. 如果ClassUtils类的类加载器为空,那么则表示是Bootstrap类加载器加载的ClassUtils类,那么则返回系统类加载器

步骤二,就是第一个if,在我们这里的调用链上是不会进来这里的,因为typeToMatch是null;
步骤三,可看可不看,一般也不会进来这里。这是Spring表达式解析的东西。Spring表达式这个东西我估计大部分人都没用过吧…(类似EL表达式,这样来理解)
步骤四,正常来说会执行到这里,然后在这里进行类加载,并且通过反射获得class对象,代码如下所示:

	public Class<?> resolveBeanClass(@Nullable ClassLoader classLoader) throws ClassNotFoundException {
		String className = getBeanClassName();
		if (className == null) {
			return null;
		}
		Class<?> resolvedClass = ClassUtils.forName(className, classLoader);
		this.beanClass = resolvedClass;
		return resolvedClass;
	}

*2.4 AbstractAutowireCapableBeanFactory#resolveBeforeInstantiation:【实例化前】入口

(PS:终于来到这里了,这才是核心考点

方法调用链:由2.2的createBean调用过来
全路径:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#resolveBeforeInstantiation
方法注释:应用实例化前的后处理器,解析指定bean是否存在实例化前的快捷方式。

源码如下:

	protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
		Object bean = null;
		if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
			// Make sure bean class is actually resolved at this point.
			if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
				Class<?> targetType = determineTargetType(beanName, mbd);
				if (targetType != null) {
					bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
					if (bean != null) {
						bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
					}
				}
			}
			mbd.beforeInstantiationResolved = (bean != null);
		}
		return bean;
	}

方法解读:代码短短的几行。首先通过hasInstantiationAwareBeanPostProcessors看看是否有InstantiationAwareBeanPostProcessors。有,则调用对应的【实例化前】方法,即applyBeanPostProcessorsBeforeInstantiation这里才是真正干活的地方,后面介绍)。

这里有一个细节,那就是applyBeanPostProcessorsBeforeInstantiation如果返回的对象不为空,则直接调用applyBeanPostProcessorsAfterInitialization走bean的【初始化后】方法了。这说明Bean的生命周期被改变!!而且,如果这里的Bean有值的话,外层直接返回创建成功了,不会继续往下走了,如下所示:(2.2的createBean调用处代码)

Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
	return bean;
}

2.5 AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInstantiation:【实例化前】真正干活的地方

方法调用链:由2.4的resolveBeforeInstantiation调用过来
全路径:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInstantiation
方法注释:将InstantiationAwareBeanPostProcessors应用到指定的bean定义(通过类和名称),调用它们的postProcessBeforeInstantiation方法。如果返回不为空,则无需Spring帮我们实例化了

源码如下:

	@Nullable
	protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
		for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
			Object result = bp.postProcessBeforeInstantiation(beanClass, beanName);
			if (result != null) {
				return result;
			}
		}
		return null;
	}

方法解读:这里终于出现我们之前说的核心InstantiationAwareBeanPostProcessor。老样子,遍历所有的InstantiationAwareBeanPostProcessor,然后调用postProcessBeforeInstantiation()。这里只要找到一个InstantiationAwareBeanPostProcessorpostProcessBeforeInstantiation()返回不为空,则直接停止遍历。
这个方法其实隐含的意思是:在Spring帮我们实例化之前,Spring会先去找找看,用户有没有对当前beanName对应的class有自己的实例化想法,如果有,则Spring就不帮我们创建了。

2.6 AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization:第一次可能调用【初始化后】

方法调用链:由2.4的resolveBeforeInstantiation调用过来
全路径:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization
方法注释:应用初始化后方法。通常调用此方法的时候,会认为已经经过了属性填充、初始化等

源码如下:

	public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
			throws BeansException {

		Object result = existingBean;
		for (BeanPostProcessor processor : getBeanPostProcessors()) {
			Object current = processor.postProcessAfterInitialization(result, beanName);
			if (current == null) {
				return result;
			}
			result = current;
		}
		return result;
	}

方法解读:看,这里直接获取所有BeanPostProcessor 接口,然后应用postProcessAfterInitialization()方法。这里有个空判断,是接口要求这么做的。返回null表示不想继续执行剩余的BeanPostProcessor 接口

2.7 AbstractAutowireCapableBeanFactory#doCreateBean:【实例化】入口(包括后续的实例化过程)

方法调用链:由2.2的createBean调用过来
全路径:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean
方法注释:AbstractAutowireCapableBeanFactory这个类的中心方法:创建一个bean实例,填充bean实例,应用后处理器,等等

源码很长,就不截取了。在这里个方法里面,主要干了4件事情:

  1. 实例化(推断构造方法、实例化)
  2. BeanDefinition的后置处理
  3. 属性注入(实例化后、属性注入)(对的,你没看错,【实例化后】是在属性注入这个方法里面被调用的)
  4. 初始化

方法解读:正如方法注释说的,这里【创建一个bean实例,填充bean实例,应用后处理器】等等。这意味着,在这里包含了【实例化】过程中剩余的==【推断构造方法、实例化、BeanDefinition的后置处理、实例化后等】==步骤。另外,下一个章节会说的【IOC属性填充】、【IOC-Aware回调】、【IOC初始化】等阶段入口其实也是在这个方法中

*2.8 AbstractAutowireCapableBeanFactory#createBeanInstance:实例化

方法调用链:由2.7的doCreateBean调用过来
全路径:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBeanInstance
方法注释:AbstractAutowireCapableBeanFactory这个类的中心方法:创建一个bean实例,填充bean实例,应用后处理器,等等

源码如下:

 protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
        // 步骤一:再次确保类已经被加载
        Class<?> beanClass = resolveBeanClass(mbd, beanName);

        if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                    "Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
        }

        // 步骤二:使用Supplier创建对象
        Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
        if (instanceSupplier != null) {
            return obtainFromSupplier(instanceSupplier, beanName);
        }

        // 步骤三:工厂方法创建对象
        if (mbd.getFactoryMethodName() != null) {
            return instantiateUsingFactoryMethod(beanName, mbd, args);
        }

        // Shortcut when re-creating the same bean...
        boolean resolved = false;
        boolean autowireNecessary = false;
        if (args == null) {
            synchronized (mbd.constructorArgumentLock) {
                if (mbd.resolvedConstructorOrFactoryMethod != null) {
                    resolved = true;
                    autowireNecessary = mbd.constructorArgumentsResolved;
                }
            }
        }
        if (resolved) {
            if (autowireNecessary) {
                return autowireConstructor(beanName, mbd, null, null);
            }
            else {
                return instantiateBean(beanName, mbd);
            }
        }

        // 步骤四:推断构造方法
        Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
        if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
                mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
            return autowireConstructor(beanName, mbd, ctors, args);
        }

        // Preferred constructors for default construction?
        ctors = mbd.getPreferredConstructors();
        if (ctors != null) {
            return autowireConstructor(beanName, mbd, ctors, null);
        }

        // 步骤五:实例化
        return instantiateBean(beanName, mbd);
    }

方法解读:这里在实例化Bean的时候,采用了多种方式。如:

2.8.1 Supplier创建对象

Supplier,直译:供应商。
首先判断BeanDefinition中是否设置了Supplier,如果设置了则调用Supplier的get()得到对象。得直接使用BeanDefinition对象来设置Supplier,比如:

AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
beanDefinition.setInstanceSupplier(new Supplier<Object>() {
 @Override
 public Object get() {
  return new UserService();
 }
});
context.registerBeanDefinition("userService", beanDefinition);

2.8.2 工厂方法创建对象

如果没有设置Supplier,则检查BeanDefinition中是否设置了factoryMethod,也就是工厂方法,有两种方式可以设置factoryMethod,比如:
方式一:

<bean id="userService" class="com.zhouyu.service.UserService" factory-method="createUserService" />

对应的UserService类为:

public class UserService {

 public static UserService createUserService() {
  System.out.println("执行createUserService()");
  UserService userService = new UserService();
  return userService;
 }

 public void test() {
  System.out.println("test");
 }

}

方式二:

<bean id="commonService" class="com.zhouyu.service.CommonService"/>
<bean id="userService1" factory-bean="commonService" factory-method="createUserService" />

对应的CommonService的类为:

public class CommonService {

 public UserService createUserService() {
  return new UserService();
 }
}

Spring发现当前BeanDefinition方法设置了工厂方法后,就会区分这两种方式,然后调用工厂方法得到对象。
值得注意的是,我们通过@Bean所定义的BeanDefinition,是存在factoryMethod和factoryBean的,也就是和上面的方式二非常类似,@Bean所注解的方法就是factoryMethod,AppConfig对象就是factoryBean。如果@Bean所所注解的方法是static的,那么对应的就是方式一。

2.8.3 构造方法创建对象

RT。

2.9 AbstractAutowireCapableBeanFactory#autowireConstructor:推断构造方法

方法调用链:由2.7的createBeanInstance调用过来
全路径:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#autowireConstructor
方法注释:推断构造方法,并且创建对象。

代码好长,我就不截取了。这里的代码看不看都还好,主要还是理解流程跟原则就好。

  1. 如果一个类只有一个构造方法,不管这个构造方法是有参还是无参,Spring都会使用这个构造方法创建对象
  2. 如果有多个构造方法,则看有没有无参构造方法。因为无参构造方法有默认的含义,若有,则选择无参的构造方法创建对象;
  3. 如果有多个构造方法,且没有无参,则看构造方法上是否有@Autowired注解,有就选择,没有就报错

额外的,在推断构造方法逻辑中除开会去选择构造方法以及查找入参对象意外,会还判断是否在对应的类中是否存在使用**@Lookup注解**了方法。如果存在则把该方法封装为LookupOverride对象并添加到BeanDefinition中。

在实例化时,如果判断出来当前BeanDefinition中没有LookupOverride,那就直接用构造方法反射得到一个实例对象。如果存在LookupOverride对象,也就是类中存在@Lookup注解了的方法,那就会生成一个代理对象。
@Lookup注解就是方法注入,使用demo如下:

@Component
public class UserService {

 private OrderService orderService;

 public void test() {
  OrderService orderService = createOrderService();
  System.out.println(orderService);
 }

 @Lookup("orderService")
 public OrderService createOrderService() {
  return null;
 }

}

2.10 AbstractAutowireCapableBeanFactory#applyMergedBeanDefinitionPostProcessors:BeanDefinition后置处理

方法调用链:由2.7的doCreateBean调用过来
全路径:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyMergedBeanDefinitionPostProcessors
方法注释:将MergedBeanDefinitionPostProcessors应用于指定的bean定义,调用它们的postProcessMergedBeanDefinition方法。

源码如下:

protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) {
		for (MergedBeanDefinitionPostProcessor processor : getBeanPostProcessorCache().mergedDefinition) {
			processor.postProcessMergedBeanDefinition(mbd, beanType, beanName);
		}
	}

方法解读:Bean对象实例化出来之后,接下来就应该给对象的属性赋值了。在真正给属性赋值之前,Spring又提供了一个扩展点,即当前的MergedBeanDefinitionPostProcessors。这里的主要难点还是,这种类型的BeanPostProcessor的应用场景,可能才是大家比较关心的。那你们觉得,这里的主要应用场景应该是什么呢?其实,按照Spring的生命周期来说,他现在提供给你的拓展点,只能是【实例化】阶段后的生命周期了,毕竟过去已经发生的已经没办法改变。所以,我们可以在这里,干预【初始化】这个阶段,如下示例:

public static void main(String[] args) {
      AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
      Object newUser = context.getBean("user");
      System.out.println(newUser);
}

// 声明bean
@Component
public class User {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void myInit() {
        System.out.println("这是我自己指定的初始化方法");
    }
}

// 声明一个MergedBeanDefinitionPostProcessor,然后改变了User这个Bean的初始化方法
@Component
public class MyBeanPostProcessor implements MergedBeanDefinitionPostProcessor {
    @Override
    public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
        if (beanName.equals("user")) {
            beanDefinition.setInitMethodName("myInit");
        }
    }
}

PS:在Spring源码中,AutowiredAnnotationBeanPostProcessor就是一个MergedBeanDefinitionPostProcessor,它的postProcessMergedBeanDefinition()中会去查找注入点,并缓存在AutowiredAnnotationBeanPostProcessor对象的一个Map中(injectionMetadataCache),为依赖注入做准备。

2.11 AbstractAutowireCapableBeanFactory#populateBean:属性注入(包含:实例化后)

(PS:属性注入不是我们这里需要关注的地方,但因为【实例化后】在这个方法里面,所以就只能点进来了)

方法调用链:由2.7的doCreateBean调用过来
全路径:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean
方法注释:使用来自bean定义的属性值在给定的BeanWrapper中填充bean实例(属性填充/依赖注入)。

populateBean中关键源码如下:

	if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
			for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
				if (!bp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
					return;
				}
			}
		}

方法解读:在处理完BeanDefinition后,Spring又设计了一个扩展点:InstantiationAwareBeanPostProcessorpostProcessAfterInstantiation(),比如:

@Component
public class ZhouyuInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {

 @Override
 public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {

  if ("userService".equals(beanName)) {
   UserService userService = (UserService) bean;
   userService.test();
  }

  return true;
 }
}

上述代码就是对userService所实例化出来的对象进行处理。这个扩展点,在Spring源码中基本没有怎么使用。估计是为了后面拓展做准备

方法总结后

以后可能不这么写了,挺麻烦的。我这样圈关键方法跟链路的原因,纯粹是想加深自己的印象,我也不知道放出来给大伙看,你们能否学习到什么。

三、实例化逻辑流程图

在这里插入图片描述

学习总结

  1. 学习了实例化的过程
  2. 学习了实例化过程中用到的2种【Bean后置处理器】:InstantiationAwareBeanPostProcessorMergedBeanDefinitionPostProcessor以及他们内部的一些方法

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

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

相关文章

iOS 17 测试版中 SwiftUI 视图首次显示时状态的改变导致动画“副作用”的解决方法

问题现象 精彩的 SwiftUI 动画可以让我们的 App 活灵活现、精妙绝伦。不过原本正常的动画在测试版本的 iOS 里却有着让码农持续秃头的“副作用”&#xff1a; 我们希望在视图首次显示时驱动状态改变来产生橘色小球围绕红球旋转的动画&#xff0c;红球应该始终保持在屏幕中心。…

Flink的Standalone部署实战

在Flink是通用的框架&#xff0c;以混合和匹配的方式支持部署不同场景&#xff0c;而Standalone单机部署方便快速部署&#xff0c;记录本地部署过程&#xff0c;方便备查。 环境要求 1&#xff09;JDK1.8及以上 2&#xff09;flink-1.14.3 3&#xff09;CentOS7 Flink相关信…

腾讯24届校招内推

校招开始啦&#xff5e;有兴趣的话可以扫我的码投&#xff0c;也可以分享给身边找工作的同学&#xff5e; ❤投递攻略 1️⃣腾讯校招步骤&#xff0c;先微信扫码绑定内推关系&#xff0c;后在电脑上上传更改简历和部门投递 2️⃣投递时将选择投递部门&#xff0c;投递后将在…

实战项目-在线学院 阿里云视频的操作

一 阿里云视频 1.1 阿里视频上传 1.2 阿里云视频上传

Vue3 Vuex状态管理多组件传递数据简单应用

去官网学习→安装 | Vuex cd 项目 安装 Vuex&#xff1a; npm install --save vuex 或着 创建项目时勾选Vuex vue create vue-demo ? Please pick a preset: Manually select features ? Check the features needed for your project: (Press <space> to se…

RocketMQ主题下的队列只有两个被订阅

一、场景 主题下的队列只有两个被订阅 二、消费者 一共有两个消费者 Consumer1 所在消费组&#xff1a;C_TEST_1订阅主题&#xff1a;fsc_wb_ccs_web_orderly_84 Consumer2 所在消费组&#xff1a;C_TEST_1订阅主题&#xff1a;fsc_wb_ccs_web_84 三、原因 两个不同的消…

预演攻击:谁需要网络靶场,何时需要

"网络演习 "和 "网络靶场 "几乎是当今信息安全领域最流行的词汇。与专业术语不同的是&#xff0c;这些词对于企业和高级管理人员来说早已耳熟能详&#xff1a;法律要求他们进行演习&#xff0c;包括网络演习&#xff0c;而网络射击场也经常在企业界和媒体上…

数据生成 | MATLAB实现WGAN生成对抗网络数据生成

数据生成 | MATLAB实现WGAN生成对抗网络数据生成 目录 数据生成 | MATLAB实现WGAN生成对抗网络数据生成生成效果基本描述程序设计参考资料 生成效果 基本描述 1.WGAN生成对抗网络&#xff0c;数据生成&#xff0c;样本生成程序&#xff0c;MATLAB程序&#xff1b; 2.适用于MATL…

美能达打印机刷卡扫描文件后,用户收不到扫描邮件

环境: 柯尼卡美能达一体机 bizhub 287 域服务器 Windows server 2019 问题描述: 新员工在域服务器创建账户后同步到打印服务器上面,他们在打印机扫描文件后,自动发邮件那个邮箱上没有他们邮件,导致他们也收不到邮件 正常是用户在打印机上刷卡后扫描件文件为PDF格式,…

Jmeter 连接 MySQL 数据库脚本

1、创建线程组 2、创建 JDBC Connection Configuration 3、创建 JDBC Request 4、最终创建的目录 5、重点来了 5.1 在百度中下载个 MySQL-connector-Java-8.0.28.jar&#xff0c;放在 jmeter 的 bin 目录下 5.2 在测试计划中&#xff0c;将 jar 包添加到脚本中 5.3 输入参…

您可以购买 Banana Pi BPI-CM2 而不是 Raspberry Pi CM4。它提供什么?

最近&#xff0c;Banana Pi&#xff08;SINOVOIP&#xff09;推出了Banana Pi BPI-CM2系统级模块&#xff08;SoM&#xff09;。BPI-CM2 是类似于Raspberry Pi CM4 的计算模块&#xff0c;提供一系列令人印象深刻的功能。Banana BPI-CM2 SoM 采用Rockchip RK3568四核 Cortex-A5…

MMdetection在VisDrone2019上训练FCOS和CenterNet

配置环境 Python 3.5>PyTorch 1.1>CUDA 9.0NCCL 2>GCC 4.9mmcv‘’ 把mmdetection的代码下载下来 git clone https://github.com/open-mmlab/mmdetection.git进入这个mmdetection文件,准备编译mmdetection的文件 cd mmdetection 装一下下面这些包&#xff0c; #…

Three.js--》✨ 阳 光 dua 郎 大 男 孩 ✨——阿伟的自述

不要让鲲流太嚣张&#xff0c;我们杰流才是最弔的 ———— 阳光dua郎大男孩 目录 项目搭建 初始化three.js基础代码 获取项目所需素材 加载图片语音模型 今天简单实现一个three.js的3D故事小游戏&#xff0c;加强自己对three知识的掌握与学习&#xff0c;只有在项目中才能…

YOLOv5基础知识入门(7)— NMS(非极大值抑制)原理解析

前言&#xff1a;Hello大家好&#xff0c;我是小哥谈。NMS是指非极大值抑制&#xff08;non maximum suppression&#xff09;&#xff0c;它是一种常用于物体检测任务的算法。在物体检测中&#xff0c;通常会有多个预测框&#xff08;bounding box&#xff09;被提议出来&…

3D图像驱动live2d--Kalidokit--人脸动作捕捉

3D图像驱动live2d–Kalidokit 可在线实时根据摄像头中人脸动作实现动作捕捉 Kalidokit https://kit.kalidoface.com/live2d/ https://github.com/yeemachine/kalidokit

Spring系列篇--关于AOP【面向切面】的详解

目录 一.AOP是什么 二.案例演示 1.前置通知1.1 先准备接口 1.2然后再准备好实现类 1.3对我们的目标对象进行JavaBean配置 1.4 编写前置系统日志通知 1.5配置系统通知XML中的JavaBean 1.6 配置代理XML中的JavaBean 1.7 测试代码开始测试 注意这里有一个报错问题&…

谷歌在Chrome浏览器中推进抗量子加密技术

近日&#xff0c;Chromium博客上发表的一篇博文称&#xff0c;为了加强网络安全&#xff0c;应对迫在眉睫的量子计算机威胁&#xff0c;谷歌各个团队密切合作&#xff0c;为网络向抗量子密码学的过渡做好准备。 谷歌的Chrome团队在博客中写道&#xff0c;该项目涉及修订技术标准…

python3实现线性规划求解

Background 对于数学规划问题&#xff0c;有很多的实现。MatlabYALMIPCPLEX这个组合应该是比较主流的&#xff0c;尤其是在电力相关系统中占据着比较重要的地位。MATLAB是一个强大的数值计算工具&#xff0c;用于数学建模、算法开发和数据分析。Yalmip是一个MATLAB工具箱&#…

VS2022 CMake报错解决小结

目录 一、问题背景 二、问题分析 三、问题解决 一、问题背景 VS2022中能够跨平台的工程类型就是CMake项目&#xff0c;一套代码能跨windows/Linux/Mac多种操作系统。而实际使用时&#xff0c;发现相关资料比较少&#xff0c;需要摸索一下。 碰到的问题简述&#xff1a; 1、C…

VMware虚拟机Ubuntu无法连接网络的解决方法

一、解决办法 网络适配器设置 终端依次执行下面命令即可 sudo nmcli networking off sudo nmcli networking onsudo service network-manager start #或者 sudo service NetworkManager start成功出现这个图标&#xff0c;即代表网络连接成功。