Spring Bean生命周期doCreateBean源码阅读

2023-11-07

 

bean的生命周期的几个后置接口都是在这个方法里面调用,所以单独开一篇该方法的源码阅读

下面从两个点来阅读:

1.何时调用(只看容器启动)

2.梳理这个方法的流程(跟上一节对应上

先贴上源码:

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

		// Instantiate the bean.
		BeanWrapper instanceWrapper = null;
		if (mbd.isSingleton()) {
			// factoryBeanObjectCache:存的是beanName对应的FactoryBean.getObject()所返回的对象
			// factoryBeanInstanceCache:存的是beanName对应的FactoryBean实例对象
			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
		}

		// 2、实例化
		if (instanceWrapper == null) {
			// 创建bean实例  new USerSerive()
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}

		// 原始对象
		final Object bean = instanceWrapper.getWrappedInstance();
		Class<?> beanType = instanceWrapper.getWrappedClass();
		if (beanType != NullBean.class) {
			mbd.resolvedTargetType = beanType;
		}

		// Allow post-processors to modify the merged bean definition.
		synchronized (mbd.postProcessingLock) {
			if (!mbd.postProcessed) {
				try {
					// 运行修改合并好了的BeanDefinition
					// 这里会查找@Autowired的注入点(InjectedElement),并把这些注入点添加到mbd的属性externallyManagedConfigMembers中
					applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
				}
				catch (Throwable ex) {
					throw new BeanCreationException(mbd.getResourceDescription(), beanName,
							"Post-processing of merged bean definition failed", ex);
				}
				mbd.postProcessed = true;
			}
		}

		// Eagerly cache singletons to be able to resolve circular references
		// even when triggered by lifecycle interfaces like BeanFactoryAware.
		// 如果当前创建的是单例bean,并且允许循环依赖,并且还在创建过程中,那么则提早暴露
		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");
			}
			// 此时的bean还没有完成属性注入,是一个非常简单的对象
			// 构造一个对象工厂添加到singletonFactories中
			// 第四次调用后置处理器
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));  // AService
		}

		// Initialize the bean instance.
		// 对象已经暴露出去了
		Object exposedObject = bean;
		try {
			// 3、填充属性 @Autowired
			populateBean(beanName, mbd, instanceWrapper);  //

			// 4、 初始化 和 BeanPostProcessor 正常AOP  BeanPostProcessor
			exposedObject = 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);
			}
		}

		if (earlySingletonExposure) {
			// 在解决循环依赖时,当AService的属性注入完了之后,从getSingleton中得到AService AOP之后的代理对象
			Object earlySingletonReference = getSingleton(beanName, false);  // earlySingletonObjects
			if (earlySingletonReference != null) {
				// 如果提前暴露的对象和经过了完整的生命周期后的对象相等,则把代理对象赋值给exposedObject
				// 最终会添加到singletonObjects中去
				if (exposedObject == bean) {  //
					exposedObject = earlySingletonReference;
				}
				// 如果提前暴露的对象和经过了完整的生命周期后的对象不相等
				// allowRawInjectionDespiteWrapping表示在循环依赖时,只能
				else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
					String[] dependentBeans = getDependentBeans(beanName);
					Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
					for (String dependentBean : dependentBeans) {
						if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
							actualDependentBeans.add(dependentBean);
						}
					}
					if (!actualDependentBeans.isEmpty()) {
						// AService的原始对象被注入给了其他bean,但是AService最后被包装了
						// 也就是说其他bean没有用到AService的最终版本
						throw new BeanCurrentlyInCreationException(beanName,
								"Bean with name '" + beanName + "' has been injected into other beans [" +
								StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
								"] in its raw version as part of a circular reference, but has eventually been " +
								"wrapped. This means that said other beans do not use the final version of the " +
								"bean. This is often the result of over-eager type matching - consider using " +
								"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
					}
				}
			}
		}

		// Register bean as disposable.
		try {
			registerDisposableBeanIfNecessary(beanName, bean, mbd);
		}
		catch (BeanDefinitionValidationException ex) {
			throw new BeanCreationException(
					mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
		}

		return exposedObject;
	}

1.何时调用(只看容器启动)

咱们现在只看UserService 这个类的创建,其余的后续在分析。

还是一样,咱们打上条件断点:

启动测试代码:

由上面可以看到,先执行实例化的后置处理器TestInstantiationAwareBeanPostProcessor的前置方法,查看调用栈针可以看到是在创建AnnotationConfigApplicationContext时候在refresh()里

// Instantiate all remaining (non-lazy-init) singletons.
// 完成beanFactory的初始化(实例化非懒加载的单例bean)
finishBeanFactoryInitialization(beanFactory);
createBean()方法,源码如下:
@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;

		// Make sure bean class is actually resolved at this point, and
		// clone the bean definition in case of a dynamically resolved Class
		// which cannot be stored in the shared merged bean definition.
		Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
		if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
			mbdToUse = new RootBeanDefinition(mbd);
			mbdToUse.setBeanClass(resolvedClass);
		}

		// Prepare method overrides.
		try {
			// 对通过XML定义的bean中的look-up方法进行预处理
			// 对于@Lookup注解标注的方法不在这里进行处理,@AutowiredAnnotationBeanPostProcessor会处理@Lookup注解
			// 不研究了
			mbdToUse.prepareMethodOverrides();
		}
		catch (BeanDefinitionValidationException ex) {
			throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
					beanName, "Validation of method overrides failed", ex);
		}

		try {
			// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
			// 1、实例化前 null
			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   Spring自带的创建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);
		}
	}

该方法也是抽象工厂类的方法:

简单分析下该方法的流程:

1.对传过来的RootBeanDefinition进行一些处理

2.然后调用实例化前的方法

3.最后去调用doCreateBean方法生成一个object 对象

所以UserService创建的时候会createBean()方法,然后按上面的流程调用到doCreateBean方法。

 

2.梳理这个方法doCreateBean的流程

		BeanWrapper instanceWrapper = null;
		if (mbd.isSingleton()) {
			// factoryBeanObjectCache:存的是beanName对应的FactoryBean.getObject()所返回的对象
			// factoryBeanInstanceCache:存的是beanName对应的FactoryBean实例对象
			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
		}

(1)判断是否单例,清除掉工厂缓存池factoryBeanInstanceCache的实例的包装器

 

// 2、实例化
		if (instanceWrapper == null) {
			// 创建bean实例  new USerSerive()
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}

(2)实例化:这里面会推断构造方法,如果没有就按无参构造方法实例

 

		// 原始对象
		final Object bean = instanceWrapper.getWrappedInstance();
		Class<?> beanType = instanceWrapper.getWrappedClass();
		if (beanType != NullBean.class) {
			mbd.resolvedTargetType = beanType;
		}

		// Allow post-processors to modify the merged bean definition.
		synchronized (mbd.postProcessingLock) {
			if (!mbd.postProcessed) {
				try {
					// 运行修改合并好了的BeanDefinition
					// 这里会查找@Autowired的注入点(InjectedElement),并把这些注入点添加到mbd的属性externallyManagedConfigMembers中
					applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
				}
				catch (Throwable ex) {
					throw new BeanCreationException(mbd.getResourceDescription(), beanName,
							"Post-processing of merged bean definition failed", ex);
				}
				mbd.postProcessed = true;
			}
		}

(3)这个点是接口MergedBeanDefinitionPostProcessor的扩展点:在BeanPostProcessor的基础上增加了在实例化和实例化后之间的扩展点,也是继承BeanPostProcessor接口。

接口源码:

public interface MergedBeanDefinitionPostProcessor extends BeanPostProcessor {

	/**
	 * Post-process the given merged bean definition for the specified bean.
	 * @param beanDefinition the merged bean definition for the bean
	 * @param beanType the actual type of the managed bean instance
	 * @param beanName the name of the bean
	 * @see AbstractAutowireCapableBeanFactory#applyMergedBeanDefinitionPostProcessors
	 */
	void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName);

	/**
	 * A notification that the bean definition for the specified name has been reset,
	 * and that this post-processor should clear any metadata for the affected bean.
	 * <p>The default implementation is empty.
	 * @param beanName the name of the bean
	 * @since 5.1
	 * @see DefaultListableBeanFactory#resetBeanDefinition
	 */
	default void resetBeanDefinition(String beanName) {
	}

}
// Eagerly cache singletons to be able to resolve circular references
		// even when triggered by lifecycle interfaces like BeanFactoryAware.
		// 如果当前创建的是单例bean,并且允许循环依赖,并且还在创建过程中,那么则提早暴露
		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");
			}
			// 此时的bean还没有完成属性注入,是一个非常简单的对象
			// 构造一个对象工厂添加到singletonFactories中
			// 第四次调用后置处理器
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));  // AService
		}

(4)这部分也是在实例化的一些操纵,设计到AbstractAutowireCapableBeanFactory的一些属性操做,总之为之后做准备(没有深入去了解)

 

// Initialize the bean instance.
		// 对象已经暴露出去了
		Object exposedObject = bean;
		try {
			// 3、填充属性 @Autowired
			populateBean(beanName, mbd, instanceWrapper);  //

			// 4、 初始化 和 BeanPostProcessor 正常AOP  BeanPostProcessor
			exposedObject = 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);
			}
		}

(5)这部分就是属性填充和初始化了

populateBean(beanName, mbd, instanceWrapper);里面会调用实例化后InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation方法

// 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,控制对象的属性注入
		// 我们可以自己写一个InstantiationAwareBeanPostProcessor,然后重写postProcessAfterInstantiation方法返回false,那么则不会进行属性填充了
		if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
			for (BeanPostProcessor bp : getBeanPostProcessors()) {
				if (bp instanceof InstantiationAwareBeanPostProcessor) {
					InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
					if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
						return;
					}
				}
			}
		}

这里判断执行的该方法返回是True 和false 如果false 就直接结束,后续不再进行属性填充,反之就会去执行InstantiationAwareBeanPostProcessor.postProcessProperties方法。

属性填充完了,再看初始化initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd)

	protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
		if (System.getSecurityManager() != null) {
			AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
				invokeAwareMethods(beanName, bean);
				return null;
			}, getAccessControlContext());
		}
		else {
			// 4.1、执行Aware
			invokeAwareMethods(beanName, bean);
		}

		Object wrappedBean = bean;
		if (mbd == null || !mbd.isSynthetic()) {
			// 4.2、初始化前
			wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
		}

		try {
			// 4.3、初始化
			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()) {
			// 4.4、初始化后 AOP  ()
			wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
		}

		return wrappedBean;
	}
 
if (System.getSecurityManager() != null) {
			AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
				invokeAwareMethods(beanName, bean);
				return null;
			}, getAccessControlContext());
		}
		else {
			// 4.1、执行Aware
			invokeAwareMethods(beanName, bean);
		}

进来就开始执行前置Aware:

BeanNameAware
BeanClassLoaderAware
BeanFactoryAware
Object wrappedBean = bean;
		if (mbd == null || !mbd.isSynthetic()) {
			// 4.2、初始化前
			wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
		}

然后初始化前的代码BeanPostProcessor.postProcessBeforeInitialization

首先AnnotationConfigApplicationContext.postProcessBeforeInitialization

	@Override
	@Nullable
	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		if (!(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
				bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
				bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)){
			return bean;
		}

		AccessControlContext acc = null;

		if (System.getSecurityManager() != null) {
			acc = this.applicationContext.getBeanFactory().getAccessControlContext();
		}

		if (acc != null) {
			AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
				invokeAwareInterfaces(bean);
				return null;
			}, acc);
		}
		else {
			invokeAwareInterfaces(bean);
		}

		return bean;
	}

执行了上一节后续的几个Aware

后续还有很多BeanPostProcessor的处理暂时不分析

最后执行我们自己的BeanPostProcessor.postProcessBeforeInitialization(跟排序有关,暂时没测试)

然后是初始化:

try {
			// 4.3、初始化
			invokeInitMethods(beanName, wrappedBean, mbd);
		}
		catch (Throwable ex) {
			throw new BeanCreationException(
					(mbd != null ? mbd.getResourceDescription() : null),
					beanName, "Invocation of init method failed", ex);
		}

这里面会执行InitializingBean.afterPropertiesSet方法;

最后是初始化后的BeanPostProcessor.postProcessAfterInitialization:

if (mbd == null || !mbd.isSynthetic()) {
			// 4.4、初始化后 AOP  ()
			wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
		}

到这一不可以看到上一节的bean生命周期的流程都执行完了

 

(6)后面的暂时先不分析,循环依赖问题。

 

总结:

根据上一节的生命周期的内容分析createBean里面的doCreateBean内容。总而言之:

1.doCreateBean是在createBean后面调用的,在createBean方法会执行InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation

2.然后在执行doCreateBean方法,首先先实例化

3.然后在属性填充的那里首选会执行InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation

4.属性填充完,马上就开始初始化,进来就开始执行前置Aware:

BeanNameAware
BeanClassLoaderAware
BeanFactoryAware

5.利用AnnotationConfigApplicationContext.postProcessBeforeInitialization的前置方法执行后续的Aware,如果有

6.执行自己的BeanPostProcessor.postProcessBeforeInitialization(跟排序有关,暂时先这样分析)

7.初始化,这里面会执行InitializingBean.afterPropertiesSet方法;

8.最后是初始化后的BeanPostProcessor.postProcessAfterInitialization

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Spring Bean生命周期doCreateBean源码阅读 的相关文章

随机推荐

  • Qt TCP 网络通信01

    概念 windows 和 Linux 套接字相似 局域网和广域网 局域网 将一定区域内各种计算机 外部通信设备和数据库连接起来形成计算机通信的私有网络 广域网 又称广域网 外网 公网 是连接不同地区局域网或城域网的远程公共网络 TCP UD
  • FPAG的上电配置的3种方法

    目前 大多数FPGA芯片是基于SRAM 的结构的 而 SRAM 单元中的数据掉电就会丢失 因此系统上电后 必须要由配置电路将正确的配置数据加载到 SRAM 中 此后 FPGA 才能够正常的运行 常见的配置芯片有EPCS 芯片 EPCS4 E
  • 【图解HTTP】(二)IP、TCP和DNS

    图解HTTP 二 IP TCP和DNS 一 负责传输的IP协议 二 确保可靠性的TCP协议 三 负责域名解析的DNS服务器 四 IP TCP和DNS三者与HTTP的关系 一 负责传输的IP协议 IP协议 即Internet Protocol
  • net6授权认证源码详解(三)

    授权 接下来跟着源码来一起学习授权相关知识 一般的service注入服务方式有如下 builder Services AddAuthorization option gt 增加授权策略 option AddPolicy Api1 build
  • 【spring】ApplicationContext详解

    ApplicationContext到底是什么 父类HierarchicalBeanFactory 拥有获取父BeanFactory的功能 父类ListableBeanFactory 拥有获取beanNames的功能 父类ResourceP
  • Redis离线安装

    Redis离线安装 目标 离线安装redis 设置redis访问权限 配置redis密码 离线安装redis 下载redis 地址 https redis io download redis downloads 下载完成后将redis拷贝到
  • 大数据项目实训总结_大数据分析必备知识点总结

    今天给大家分享一篇关于大数据分析必备知识点总结 下面我们一起来看一下吧 1 数据 信息和知识是广义数据表现的不同形式 2 主要知识模式类型有 广义知识 关联知识 类知识 预测型知识 特异型知识3 web挖掘研究的主要流派有 Web结构挖掘
  • 绝杀 GETPOST 嵌套的 JSON 参数

    JSON JavaScript Object Notation 是一种轻量级的数据交换格式 常用于Web应用程序中的数据传输 在HTTP数据包信息传递时 JSON扮演着非常正常的角色 因为它是一种通用的数据格式 可以被多种编程语言和应用程序
  • Python笔记_列表

    Python笔记 列表 列表的常用操作 任意定义两个列表 list one 1 2 3 14 python list two 1 10 55 20 6 计算序列的长度 print len list one 返回序列最小元素 注意 不同的类型
  • 液晶屏的接口信号RGB_TTL、LVDS、MIPI

    RGB TTL信号是TFT LCD能识别的标准信号 就算是以后用到的LVDS TMDS 都是在它的基础上编码得来的 RGB TTL信号可分为数据信号RGB 行同步信号HS 场同步信号VS 时钟信号CLK 使能信号DE 其中R G G三基色中
  • C# 线程暂停和恢复

    文章目录 前言 一 暂停与恢复 二 功能实现 1 按钮事件 播放和停止 2 线程和ManualResetEvent 总结 前言 因为需要一个自动播放和暂停图片的功能 所以就非常自然想到了创建一个线程 用点击事件控制线程的暂停和启动 一 暂停
  • [Windows驱动开发](四)内存管理

    一 内存管理概念 1 物理内存概念 Physical Memory Address PC上有三条总线 分别是数据总线 地址总线和控制总线 32位CPU的寻址能力为4GB 2的32次方 个字节 用户最多可以使用4GB的真实物理内存 PC中很多
  • PyTorch简介

    PyTorch是一个针对深度学习 并且使用GPU和CPU来优化的tensor library 张量库 最新发布的稳定版本为1 9 源码在https github com pytorch pytorch 它支持在Linux Mac和Windo
  • kafka启动失败,报错java.lang.NoSuchMethodError

    ERROR KafkaServer id 1 Fatal error during KafkaServer startup Prepare to shutdown kafka server KafkaServer java lang NoS
  • Java迭代器和Collection接口

    各位小伙伴们大家好 欢迎来到这个小扎扎的 Java核心技术 卷 笔记专栏 在这个系列专栏中我将记录浅学这本书所得收获 鉴于 看到就是学到 学到就是赚到 精神 这波简直就是血赚 涉及的知识点速通 关于迭代器你都知道什么 什么是迭代器 迭代器的
  • 机智云GoKit3点灯教程(基于正点原子的代码风格)

    首先的首先 吐槽一波机智云的教程 官方的教程总是让下它那个微信宠物屋的代码 一步看结果 拜托 就不能来个一步一步地教程吗 还有那个宠物屋的代码看得很头痛啊 总而言之 官方的教程给我的感觉就是很凌乱 按习惯 拿到板子先点个灯 下面就来一步一步
  • java tomcat get url地址长度如何设置_解决Springboot get请求是参数过长的情况

    问题原因 Springboot get请求是参数过长抛出异常 Request header is too large 的问题 错误描述 java lang IllegalArgumentException Request header is
  • sonarQube10.0代码审计软件安装(一)

    sonarQube10 0代码审计软件安装 一 下载地址 官网 可能需要科学上网一下 安装教程 选择Try out SonarQube 页面中即可发现Installing a local instance of SonarQube 下方即为
  • linux2——GDB调试,makefile规则(比之前的深一点点)

    一 常用gdb指令一览 二 makefile 1 超简单例子 2 基本规则 在替换之前 能看懂之前 3 经过替换开始一眼看不懂 4 但是即便经过3的变换也无法做到 自动化扩展 比如加一个乘法函数就需要再写一个乘法的规则 因此有模式规则 o
  • Spring Bean生命周期doCreateBean源码阅读

    bean的生命周期的几个后置接口都是在这个方法里面调用 所以单独开一篇该方法的源码阅读 下面从两个点来阅读 1 何时调用 只看容器启动 2 梳理这个方法的流程 跟上一节对应上 先贴上源码 protected Object doCreateB