96SEO 2026-02-19 17:43 11
专家博主系列专栏Java设计模式、数据结构和算法、Kafka从入门到成神、Kafka从成神到升仙、Spring从成神到升仙系列如果感觉博主的文章还不错的话请三连支持一下博主哦博主正在努力完成2023计划中以梦为马扬帆起航2023追梦人联系方式hls1793929520和大家一起学习一起进步

源码剖析1、prepareRefresh2、obtainFreshBeanFactory2.1
refreshBeanFactory3、prepareBeanFactory4、postProcessBeanFactory5、invokeBeanFactoryPostProcessors6、registerBeanPostProcessors7、initMessageSource8、initApplicationEventMulticaster9、onRefresh10、registerListeners11、finishBeanFactoryInitialization11.1
初始化逻辑12、finishRefresh13、销毁五、流程图六、总结七、附录1、注册别名的原因2、BeanFactoryPostProcessor
BeanDefinitionRegistryPostProcessor3、BeanFactoryPostProcessor
BeanDefinitionRegistryPostProcessorSpring
但随着目前程序员行业的发展我们有必要打开这个黑盒去探索其中的奥妙。
源码文章的错误将不再一行一行的带大家分析源码我们将一些不重要的部分当做黑盒处理以便我们更快、更有效的阅读源码。
这里讲个小细节如果你在面试这里一定要提前给面试官说好你阅读的源码版本有三方面好处
第一避免不同版本的Spring源码不一致导致和面试官的分歧问题
第二让面试官感觉你小子是真的阅读过源码就算你说的逻辑和面试官有分歧面试官第一反应会是源码版本差异导致的
dependencygroupIdorg.springframework/groupIdartifactIdspring-context/artifactIdversion4.3.11.RELEASE/version
xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsdbean
classcn.hls.spring.MessageServiceImpl/
ClassPathXmlApplicationContext(application.xml);System.out.println(context
context.getBean(MessageService.class);//
worldSystem.out.println(messageService.getMessage());}
ClassPathXmlApplicationContext(application.xml);
ClassPathXmlApplicationContext(String[]
parent){super(parent);setConfigLocations(configLocations);if
PathMathingResourcePatternResolver
解析配置文件setConfigLocations(configLocations)设置
到当前应用程序中refresh()解析配置文件、完成bean的注册、实例化、初始化、代理等一系列的工作最终创建出一个
System.currentTimeMillis();设置活跃状态为
对象中准备监听器和事件的集合对象默认为空的集合earlyApplicationEvents
LinkedHashSetApplicationEvent();
这个方法不重要也不必要去深入了解知道做了容器刷新的准备工作即可。
DefaultListableBeanFactoryDefaultListableBeanFactory
createBeanFactory();beanFactory.setSerializationId(getId());customizeBeanFactory(beanFactory);loadBeanDefinitions(beanFactory);synchronized
}上述我们必须记住这个工厂类DefaultListableBeanFactory甚至要做到背诵默写的程度
loadBeanDefinitions(beanFactory)
loadBeanDefinitions(DefaultListableBeanFactory
创建XmlBeanDefinitionReader这个是我们xml文件的解析器XmlBeanDefinitionReader
XmlBeanDefinitionReader(beanFactory);beanDefinitionReader.setEnvironment(this.getEnvironment());beanDefinitionReader.setResourceLoader(this);beanDefinitionReader.setEntityResolver(new
ResourceEntityResolver(this));initBeanDefinitionReader(beanDefinitionReader);//
加载BeanDefinitionsloadBeanDefinitions(beanDefinitionReader);
loadBeanDefinitions(XmlBeanDefinitionReader
{reader.loadBeanDefinitions(configResources);}String[]
{reader.loadBeanDefinitions(configLocations);}
actualResources){ResourceLoader
resourceLoader).getResources(location);//
loadBeanDefinitions(resources);if
{actualResources.add(resource);}}return
resourceLoader.getResource(location);int
loadBeanDefinitions(resource);if
{actualResources.add(resource);}return
resource);XmlBeanDefinitionReader
registerBeanDefinitions(Document
createBeanDefinitionDocumentReader();int
getRegistry().getBeanDefinitionCount();//
其余不重要直接看这行documentReader.registerBeanDefinitions(doc,
createReaderContext(resource));return
getRegistry().getBeanDefinitionCount()
registerBeanDefinitions(Document
从根节点开始解析遍历doRegisterBeanDefinitions(root);
doRegisterBeanDefinitions(Element
createDelegate(getReaderContext(),
(this.delegate.isDefaultNamespace(root))
root.getAttribute(PROFILE_ATTRIBUTE);if
(StringUtils.hasText(profileSpec))
StringUtils.tokenizeToStringArray(profileSpec,
BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);}}preProcessXml(root);//
直接看这里其余不重要parseBeanDefinitions(root,
this.delegate);postProcessXml(root);this.delegate
(delegate.isDefaultNamespace(root))
(delegate.isDefaultNamespace(ele))
{delegate.parseCustomElement(ele);}}}}else
{delegate.parseCustomElement(root);}
根据不同的配置走不同的分支配置:import、alias、bean、beans
{importBeanDefinitionResource(ele);}else
{processAliasRegistration(ele);}else
recursedoRegisterBeanDefinitions(ele);}}我们这里只看
解析各种xml标签去生成对应的BeanDefinition读者有兴趣可以自己看一下BeanDefinitionHolder
delegate.parseBeanDefinitionElement(ele);if
delegate.decorateBeanDefinitionIfRequired(ele,
重点正式开始注册BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder,
getReaderContext().getRegistry());}getReaderContext().fireComponentRegistered(new
BeanComponentDefinition(bdHolder));}
registerBeanDefinition(BeanDefinitionHolder
definitionHolder.getBeanName();registry.registerBeanDefinition(beanName,
definitionHolder.getBeanDefinition());//
definitionHolder.getAliases();if
{registry.registerAlias(beanName,
如果已经存在我们要排抛出异常Spring不允许覆盖BeanDefinition
beanDefinitionMap.get(beanName);if
(!isAllowBeanDefinitionOverriding())
BeanDefinitionStoreException()}}if
{this.beanDefinitionMap.put(beanName,
重点在这将我们的beanName与beanDefinition放至beanDefinitionMap中this.beanDefinitionMap.put(beanName,
beanDefinition);this.beanDefinitionNames.add(beanName);this.manualSingletonNames.remove(beanName);}}到这里基本就结束了我们来回顾一下
扫描遍历对不同配置的标签import、alias、bean、beans走不同的逻辑判断将当前的标签各属性进行组装成
是否被注册过如果被注册过则直接抛出异常Spring不允许覆盖如果没有注册过则将
系列的文章大家都知道分享的很细但是我们细细品味一下我们读源码到底为了什么以及如何去读、如何有效的读、如何快速的读我相信每一个人心中都有一套读源码的方式。
至于哪一种阅读方式更为合理后面博主准备单独出一篇文章来讲解或者你可以私信我告知我你的读源码的方式一起加油、一起学习。
5、invokeBeanFactoryPostProcessors
可以自由扩展通过实现BeanFactoryPostProcessor
BeanDefinitionRegistryPostProcessor
invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory
BeanDefinitionRegistryPostProcessor接口的实现//
若这些实现有对应的order(顺序)则排序之后依次调用PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory,
getBeanFactoryPostProcessors());if
(beanFactory.getTempClassLoader()
beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME))
{beanFactory.addBeanPostProcessor(new
LoadTimeWeaverAwareProcessor(beanFactory));beanFactory.setTempClassLoader(new
ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));}
BeanDefinitionRegistryPostProcessor
registerBeanPostProcessors(ConfigurableListableBeanFactory
实例化并且注册所有的beanPostProcessorPostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory,
invokeBeanFactoryPostProcessors
里面很像都是对实现一些特定接口的类做加载但需要注意的是对于实现
BeanDefinitionRegistryPostProcessor
8、initApplicationEventMulticaster
11、finishBeanFactoryInitialization
整体简介完成所有非懒加载的单例对象的实例化操作从此方法开始进行对象的创建包含了实例化初始化循环依赖AOP等核心逻辑的处理过程此步骤是最最核心且关键的点要对其中的细节最够清楚
finishBeanFactoryInitialization(ConfigurableListableBeanFactory
实例化剩下的单例对象beanFactory.preInstantiateSingletons();
拿到我们之前存储的所有beanDefinition的名字ListString
ArrayList(this.beanDefinitionNames);
如果beanName对应的bean不是FactoryBean只是普通的bean通过beanName获取bean实例getBean(beanName);}
此方法是实际获取bean的方法也是触发依赖注入的方法return
这里需要一步转换这里的原因我们附录1提到过这里不再过多讨论String
提前检查单例缓存中是否有手动注册的单例对象剧透一下和循环依赖有关联Object
当对象都是单例的时候会尝试解决循环依赖的问题但是原型模式下如果存在循环依赖的情况那么直接抛出异常if
(isPrototypeCurrentlyInCreation(beanName))
BeanCurrentlyInCreationException(beanName);}if
返回以beanName的(原始)单例对象如果尚未注册则使用singletonFactory创建并注册一个对象:sharedInstance
为给定的合并后BeanDefinition(和参数)创建一个bean实例//
根据执行bean使用对应的策略创建新的实例如工厂方法构造函数主动注入、简单初始化BeanWrapper
对bean的属性进行填充将各个属性值注入其中可能存在依赖于其他bean的属性则会递归初始化依赖的beanpopulateBean(beanName,
我们需要进行名称转化防止传入的是一个别名或其他的名称利用转换后的别名去调用
可能大家有点懵怎么这么多创建的方法这里其实我们不需要太过于关注只需要关注
getInstantiationStrategy().instantiate(mbd,
通过class得到其默认的构造方法constructorToUse
clazz.getDeclaredConstructor();//
BeanUtils.instantiateClass(constructorToUse);}
如果当前是无参构造方法的话则argsWithDefaultValues为空return
ctor.newInstance(argsWithDefaultValues);
classcom.mashibing.hls.MessageServiceImplproperty
注入属性applyPropertyValues(beanName,
获取pvs的PropertyValue对象数组并将其转换成列表ListPropertyValue
Arrays.asList(pvs.getPropertyValues());for
因为我们的属性注入有可能注入的是一个BeanReference需要重新去
按原样使用deepCopy构造一个新的MutablePropertyValues对象然后设置到bw中以对bw的属性值更新bw.setPropertyValues(new
MutablePropertyValues(deepCopy));}
setPropertyValues(PropertyValues
setPropertyValues(PropertyValues
后续主要通过反射对值进行设置感兴趣的可以自己去看下源码实现setPropertyValue(pv);
postProcessBeforeInitialization(Object
{System.out.println(我前置增强);return
postProcessAfterInitialization(Object
{System.out.println(我后置增强);return
将BeanPostProcessors应用到给定的现有Bean实例调用它们的postProcessBeforeInitialization初始化方法。
//
返回的Bean实例可能是原始Bean包装器wrappedBean
applyBeanPostProcessorsBeforeInitialization(wrappedBean,
beanName);//调用初始化方法先调用bean的InitializingBean接口方法后调用bean的自定义初始化方法invokeInitMethods(beanName,
将BeanPostProcessors应用到给定的现有Bean实例调用它们的postProcessAfterInitialization方法。
//
返回的Bean实例可能是原始Bean包装器wrappedBean
applyBeanPostProcessorsAfterInitialization(wrappedBean,
applyBeanPostProcessorsBeforeInitialization(Object
该工厂创建的bean的BeanPostProcessors列表for
processor.postProcessBeforeInitialization(result,
{//直接返回result中断其后续的BeanPostProcessor处理return
result;}//让result引用processor的返回结果,使其经过所有BeanPostProcess对象的后置处理的层层包装result
current;}//返回经过所有BeanPostProcess对象的后置处理的层层包装后的resultreturn
在bean上调用指定的自定义init方法invokeCustomInitMethod(beanName,
ClassUtils.getInterfaceMethodIfPossible(initMethod);//
applyBeanPostProcessorsAfterInitialization(Object
beanName){//初始化结果对象为result默认引用existingBeanObject
existingBean;//遍历该工厂创建的bean的BeanPostProcessors列表for
{//回调BeanPostProcessor#postProcessAfterInitialization来对现有的bean实例进行包装Object
processor.postProcessAfterInitialization(result,
{//直接返回result中断其后续的BeanPostProcessor处理return
result;}//让result引用processor的返回结果,使其经过所有BeanPostProcess对象的后置处理的层层包装result
current;}//返回经过所有BeanPostProcess对象的后置处理的层层包装后的resultreturn
完成整个容器的启动所有的对象都准备完成可以进行后续业务流程的操作清除上下文缓存初始化生命周期处理器发送刷新完成事件
前面我们已经创建成功了对象当我们使用完成之后肯定要进行销毁那么
直接将beanFactory置为nullcloseBeanFactory();
清空在包含的Bean名称之间映射bean名称-Bean包含的Bean名称集this.containedBeanMap.clear();//
清空在相关的Bean名称之间映射bean名称-一组相关的Bean名称this.dependentBeanMap.clear();//
清空在相关的Bean名称之j键映射bean名称bean依赖项的Bean名称集this.dependenciesForBeanMap.clear();//
清除此注册表中所有缓存的单例实例clearSingletonCache();
加锁使用单例对象的高速缓存:beam名称-bean实例作为锁synchronized
清空单例对象的高速缓存:beam名称-bean实例this.singletonObjects.clear();//
清空单例工厂的缓存bean名称-ObjectFactorythis.singletonFactories.clear();//
清空早期单例对象的高速缓存bean名称-bean实例this.earlySingletonObjects.clear();//
清空已注册的单例集按照注册顺序包含bean名称this.registeredSingletons.clear();//
设置当前是否在destroySingletons中的标志为falsethis.singletonsCurrentlyInDestruction
{this.allBeanNamesByType.clear();this.singletonBeanNamesByType.clear();
{beanFactory.setSerializationId(null);this.beanFactory
classcn.hls.spring.MessageServiceImpl
init(){System.out.println(我是类的初始化);}public
destroy(){System.out.println(我是类的销毁);}
有些小伙伴可能疑惑哎博主你这不对呀你这循环依赖也没讲、三级缓存也没讲你是不是漏的有点多。
代理对象的问题这个我们后面单独出一篇来描述不要着急小黄不会不讲的。
AnnotationConfigApplicationContext
我是爱敲代码的小黄独角兽企业的Java开发工程师CSDN博客专家Java领域新星创作者喜欢后端架构和中间件源码。
canonicalName(BeanFactoryUtils.transformedBeanName(name));
(String)this.aliasMap.get(canonicalName);if
BeanDefinitionRegistryPostProcessor
postProcessBeanFactory(ConfigurableListableBeanFactory
PropertyValueMutablePropertyValues
beanFactory.getBeanDefinition(messageService).getPropertyValues();ListPropertyValue
messageService.getPropertyValueList();//
{System.out.println(BeanFactoryPostProcessor
[null]3、BeanFactoryPostProcessor
BeanDefinitionRegistryPostProcessor
postProcessBeforeInitialization(Object
{System.out.println(我会在类初始化前调用);return
postProcessAfterInitialization(Object
{System.out.println(我会在类初始化后调用);return
作为专业的SEO优化服务提供商,我们致力于通过科学、系统的搜索引擎优化策略,帮助企业在百度、Google等搜索引擎中获得更高的排名和流量。我们的服务涵盖网站结构优化、内容优化、技术SEO和链接建设等多个维度。
| 服务项目 | 基础套餐 | 标准套餐 | 高级定制 |
|---|---|---|---|
| 关键词优化数量 | 10-20个核心词 | 30-50个核心词+长尾词 | 80-150个全方位覆盖 |
| 内容优化 | 基础页面优化 | 全站内容优化+每月5篇原创 | 个性化内容策略+每月15篇原创 |
| 技术SEO | 基本技术检查 | 全面技术优化+移动适配 | 深度技术重构+性能优化 |
| 外链建设 | 每月5-10条 | 每月20-30条高质量外链 | 每月50+条多渠道外链 |
| 数据报告 | 月度基础报告 | 双周详细报告+分析 | 每周深度报告+策略调整 |
| 效果保障 | 3-6个月见效 | 2-4个月见效 | 1-3个月快速见效 |
我们的SEO优化服务遵循科学严谨的流程,确保每一步都基于数据分析和行业最佳实践:
全面检测网站技术问题、内容质量、竞争对手情况,制定个性化优化方案。
基于用户搜索意图和商业目标,制定全面的关键词矩阵和布局策略。
解决网站技术问题,优化网站结构,提升页面速度和移动端体验。
创作高质量原创内容,优化现有页面,建立内容更新机制。
获取高质量外部链接,建立品牌在线影响力,提升网站权威度。
持续监控排名、流量和转化数据,根据效果调整优化策略。
基于我们服务的客户数据统计,平均优化效果如下:
我们坚信,真正的SEO优化不仅仅是追求排名,而是通过提供优质内容、优化用户体验、建立网站权威,最终实现可持续的业务增长。我们的目标是与客户建立长期合作关系,共同成长。
Demand feedback