当前位置:首页 » 《资源分享》 » 正文

Spring原理篇(5)--为什么你跟别的程序员一起去面试.同样问的Spring的原理;别人可以拿30K 你却只能要到15K;前面三章文章的铺垫,为的就是现在<Spring真正的生命周期-中>_wenaicoo的博客

2 人参与  2021年09月27日 16:23  分类 : 《资源分享》  评论

点击全文阅读


@TOC# Spring系列
记录在程序走的每一步___auth:huf


最近在复习Spring核心原理; 顺手记录;

Spring 真正的生命周期;

在很多文章中 写到这么个标题: XXXX原理 你只要看完这一篇就够; 作为一个技术苦行憎; 老衲很直白的说一句: 不可能的. 一个技术;需要大量时间去重复调研;最终才会摸清楚其原理; 我们还是一步一脚印;慢慢往里研究; 拨开云雾见天日 守得云开见月明;欢迎各路大神指正;共同进步
本文章开销时长 要比 之前的文章开销时长要大很多 本章节一共写了9个小时 ; 各位同学 记得三连

  • 本文章 所有源码均是作者 自己从Spring源码中Copy 注释 之前有部分同学反映看不太清楚;所以把//去除以便源码的阅读;

承接周三的陈述; 我们讲到了Bean的创建; 以下是上个篇章尾部的描述:通过
1:ResourcePatternResolver获得指定包路径下的所有 .class 文件(Spring源码中将 此文件包装成了Resource对象
2:利用MetadataReaderFactory解析Resource对象得到MetadataReader(在Spring源码中 MetadataReaderFactory具体的实现类为CachingMetadataReaderFactory, MetadataReader的具体实现类为SimpleMetadataReader)
3:利用MetadataReader进行excludeFilters和includeFilters,以及条件注解@Conditional的筛选 (条件注解并不能解析某个类上是否存在@Conditional注解,如果存在则调用注解中所指定 的类的match方法进行匹配,匹配成功则通过筛选,匹配失败则pass掉。)
4.筛选通过后,基于metadataReader生成ScannedGenericBeanDefinition
5:再基于metadataReader判断是不是对应的类是不是接口或抽象类;

我们的主要目的是得到BeanDefinition 然后合成RootBeanDefinition;最后放进缓存集合中去
在这里插入图片描述
我们开始回顾; 之前的源码 就不会一遍一遍看了 如果有的 可能会一笔带过;

以下是我们创建容器的方法

 		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(testMain.class);
        Object hufFactoryBean = context.getBean("hufFactoryBean");
        System.out.println(hufFactoryBean);

再AnnotationConfigApplicationContext构造器 点进去后 我们发现 :

public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
		创建一个新的 context; 根据系统参数; 上一篇文章有讲到;
		this();
		注册Spring自己用的组件; 为创建容器 提供必须的条件; 这里不再累赘
		register(componentClasses);
		开始启动容器,重点关注该方法; 
		refresh(); 
	}

AbstractApplicationContext.refresh() 其源码我给你们带进来这里 进行每一行代码的解释;
有部分如果内容比较多的 后面会有独立的篇章 去讲解相对应的内容; 看源码请勿心急; 如果有哪个地方没看懂;可以先放一下 把整个链路串起来 然后再看; 以下 是Spring的核心源码:

@Override
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
			 检查初始化环境
			prepareRefresh();
			 通过子类获取它内部的Bean工厂 其内部有两个实现方法 如果有兴趣的同学 可以自行去查看
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
			 配置工厂的类加载器; 以及后置处理器; 内部使用了beanfactorypostprocessor 机制
			prepareBeanFactory(beanFactory);
			try {
				 所有 bean 定义都已加载,bean还没有 bean 被实例化。这里引出了实例化一个词
				postProcessBeanFactory(beanFactory);
				StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
				 实例化并调用所有已注册的 beanfactorypostprocessor 此时Bean还未实例化 
				仅仅是再处理配置文件的调度后置处理器
				invokeBeanFactoryPostProcessors(beanFactory);
				 这里开始分装与注册 PostProcessor 例如MergedBeanDefinitionPostProcessor 
				就跟普通的Processor不一样 都再这个方法内进行分装
				并且 这里创建出来了 BeanFactory 还有自己的配置 再初始化之前的接口 这里引入
				InstantiationAwareBeanPostProcessor , MergedBeanDefinitionPostProcessor
				再文章后面会有这两个接口的讲解 到这里 Bean的实例化还没有开始 更别说初始化
				registerBeanPostProcessors(beanFactory);
				这行不作解释;
				beanPostProcess.end();
				 注册messageSource; 利用AbstractBeanFactory.dogetBean方法; 进行初始化;PostProcessor 就起效果了;
				initMessageSource();
				 注册 初始化 特殊的Bean  Spring的监听机制; 
				 ApplicationListenerApplicationEventMulticaster
				initApplicationEventMulticaster();
				 初始化特定上下文子类中的其他特殊bean。 目前看源码没看到注册了什么Bean
				 在控制台也没看到有什么东西打印出来; 知道的小伙伴可以私聊 我们一起讨论
				onRefresh();
				 注册Springlistener Bean 如果你实现了Listener 就会这这里被注册
				registerListeners();
				 实例化所有 非 懒加载的 单例Bean; 本文中的重点; 
				finishBeanFactoryInitialization(beanFactory);
				 最后:发布相应的事件
				finishRefresh();
			}
			catch (BeansException ex) {
				if (logger.isWarnEnabled()) {
					logger.warn("Exception encountered during context initialization - " +
							"cancelling refresh attempt: " + ex);
				}
				 注销Bean的逻辑 放到其他章节去讲;.
				destroyBeans();
				cancelRefresh(ex);
				throw ex;
			}
			finally {
				resetCommonCaches();
				contextRefresh.end();
			}
		}
	}

上面这个方法特别重要.也引出了很多关键的接口 以及关键的初始化;

总结;

1:初始化Bean之前 就必须实例化Bean 实例化过后才会初始化; 初始化过后的Bean才是完整的Bean
2:在初始化Bean的时候 我们有可能会影响Bean的 在实例化Bean的时候 我们也可以通过 PostProcessor来影响Bean的实例化; PostProcessor 作为Spring的"插件" 例如;InstantiationAwareBeanPostProcessor MergedBeanDefinitionPostProcessor
3:所有的监听机制 Listenner 以及 ApplicationEventMulticaster 都会再Bean 注册之前创建
4:最后创建 非 懒加载 的Bean ;

以下到 我们这篇文章的重点:
// 实例化所有 非 懒加载的 单例Bean; 本文中的重点; 该句源码是在上面源码里拿到的;

finishBeanFactoryInitialization(beanFactory);

继续往下走 点进这个方法:

	protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
		 为此上下文初始化转换服务
		if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
				beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
			beanFactory.setConversionService(
					beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
		}
		 如果没有BeanFactoryPostProcessor 就进行注册; 主要用于注释属性值中的Values
		if (!beanFactory.hasEmbeddedValueResolver()) {
			beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
		}
		初始化回调 Bean 之后在其他章节中 讲解Aware; 
		这里同学可以试试 如果你实现LoadTimeWeaverAware 接口 那么就会在Bean注册之前 先注册这个Aware
		String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
		for (String weaverAwareName : weaverAwareNames) {
			getBean(weaverAwareName);
		}
		停止使用临时类加载器进行类型匹配。
		beanFactory.setTempClassLoader(null);
		允许缓存所有bean定义元数据,不需要进一步更改。
		beanFactory.freezeConfiguration();
		实例化非懒加载Bean
		beanFactory.preInstantiateSingletons();
	}

这里 不做过多的解释; 继续往下面看;

beanFactory.preInstantiateSingletons();

进入该方法

@Override
	public void preInstantiateSingletons() throws BeansException {
		if (logger.isTraceEnabled()) {
			logger.trace("Pre-instantiating singletons in " + this);
		}
		允许init方法注册新的bean定义
		List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
		这里就可以看到 得到Bean的名字集合 开始触发所有Bean的初始化;
		for (String beanName : beanNames) {
			继前面文章面熟 所有Beandefinition 最终会合并成为RootBeanDefinition,然后进行Bean的初始化;
			RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
			判断是不是抽象的Bean  判断是不是单例的Bean  判断是不是懒加载的Bean
			if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
				判断是不是工厂的Bean
				if (isFactoryBean(beanName)) {
					如果是 那么就用&符号加 BeanName 得到工厂的Bean 
					Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
					得到Bean后 进行类型判断 是不是工厂bean;
					 如果不是 那么直接调度 getBean 这段IF里面的东西先进行屏蔽;
					if (bean instanceof FactoryBean) {
						if (isEagerInit) {
							重点 重点 重点
							getBean(beanName);
						}
					}
				}
				else {
					重点 重点 重点
					getBean(beanName);
				}
			}
		}
	触发所有适用bean的初始化后回调。。。 这里就不多过的冗余下去; 
		for (String beanName : beanNames) {
			Object singletonInstance = getSingleton(beanName);
			if (singletonInstance instanceof SmartInitializingSingleton) {
				StartupStep smartInitialize = this.getApplicationStartup().start("spring.beans.smart-initialize")
						.tag("beanName", beanName);
				SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
				if (System.getSecurityManager() != null) {
					AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
						smartSingleton.afterSingletonsInstantiated();
						return null;
					}, getAccessControlContext());
				}
				else {
					smartSingleton.afterSingletonsInstantiated();
				}
				smartInitialize.end();
			}
		}
	}
getBean(beanName);

点进去GetBean 方法中

@Override
	public Object getBean(String name) throws BeansException {
		return doGetBean(name, null, null, false);
	}

继续往下点:

	@SuppressWarnings("unchecked")
	protected <T> T doGetBean(
			String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
			throws BeansException {
		获取名字; 该名字 刚进来的时候也许是别名 也许是其他的名字
		 但是最终会通过这个方法获取到Bean的真实名字
		String beanName = transformedBeanName(name);
		Object beanInstance;

		 检查单例池是否有该Bean的存在
		Object sharedInstance = getSingleton(beanName);
		if (sharedInstance != null && args == null) {
			if (logger.isTraceEnabled()) {
				if (isSingletonCurrentlyInCreation(beanName)) {
					logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
							"' that is not fully initialized yet - a consequence of a circular reference");
				}
				else {
					logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
				}
			}
			 如果有 就返回 该方法里面还会有另外一个检查 此处不做细说
			beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
		}

		else {
			如果我们已经在创建此bean实则抛出异常;
			if (isPrototypeCurrentlyInCreation(beanName)) {
				throw new BeanCurrentlyInCreationException(beanName);
			}
			检查工厂中是否存在bean定义;
			BeanFactory parentBeanFactory = getParentBeanFactory();
			如果有 就使用工厂的方法创建Bean
			if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
			 此处源码自行查看 为方便阅读 此处省略
			}
			if (!typeCheckOnly) {
				markBeanAsCreated(beanName);
			}
			Spring系统计算 程序开销时间 与容器启动 关系不大;
			StartupStep beanCreation = this.applicationStartup.start("spring.beans.instantiate")
					.tag("beanName", name);
			try {
				if (requiredType != null) {
					beanCreation.tag("beanType", requiredType::toString);
				}
				这里不再重复陈述
				RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
				checkMergedBeanDefinition(mbd, beanName, args);

				这里就要说一个注解了 @DependsOn 这个注解的意思是 在某个类初始化之前 
				另外一个类再在它之前被初始化 这里插一句话; 
				Spring解决了循环依赖 但是又没有完全解决循环依赖;
				这里的循环依赖 无法解决的  假设使用这个注解 A依赖B B依赖A 是一定会报错的;
				String[] dependsOn = mbd.getDependsOn();
				if (dependsOn != null) {
					for (String dep : dependsOn) {
						if (isDependent(beanName, dep)) {
							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
									"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
						}
						registerDependentBean(dep, beanName);
						try {
							getBean(dep);
						}
						catch (NoSuchBeanDefinitionException ex) {
							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
									"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
						}
					}
				}
				创建bean实例。
				if (mbd.isSingleton()) {
					sharedInstance = getSingleton(beanName, () -> {
						try {
							return createBean(beanName, mbd, args);
						}
						catch (BeansException ex) {
							destroySingleton(beanName);
							throw ex;
						}
					});
					beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
				}

				else if (mbd.isPrototype()) {
					这个逻辑是创建原型Bean的逻辑 也就是多例Bean
					Object prototypeInstance = null;
					try {
						初始化前
						beforePrototypeCreation(beanName);
						初始化
						prototypeInstance = createBean(beanName, mbd, args);
					}
					finally {
						初始化后
						afterPrototypeCreation(beanName);
					}
					返回
					beanInstance = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
				}

				else {
					单例bean的创建
					String scopeName = mbd.getScope();
					if (!StringUtils.hasLength(scopeName)) {
						throw new IllegalStateException("No scope name defined for bean ´" + beanName + "'");
					}
					Scope scope = this.scopes.get(scopeName);
					if (scope == null) {
						throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
					}
					try {
						Object scopedInstance = scope.get(beanName, () -> {
							初始化前
							beforePrototypeCreation(beanName);
							try {
								初始化
								return createBean(beanName, mbd, args);
							}
							finally {
								初始化后
								afterPrototypeCreation(beanName);
							}
						});
						beanInstance = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
					}
					catch (IllegalStateException ex) {
						throw new ScopeNotActiveException(beanName, scopeName, ex);
					}
				}
			}
			catch (BeansException ex) {
				beanCreation.tag("exception", ex.getClass().toString());
				beanCreation.tag("message", String.valueOf(ex.getMessage()));
				cleanupAfterBeanCreationFailure(beanName);
				throw ex;
			}
			finally {
				beanCreation.end();
			}
		}

		return adaptBeanInstance(name, beanInstance, requiredType);
	}

本文章总结:

描述了 Bean 创建的大体流程 但是销毁流程 跟属性注入 没有讲到 后面会有单独的文章进行讲解;

seeyou


点击全文阅读


本文链接:http://zhangshiyu.com/post/28865.html

初始化  源码  实例  
<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1