Spring组件扫描原理解析
Spring组件扫描原理解析一、概述用一幅图来对两种方式配置Bean的组件扫描进行一个总结二、原理剖析通过之前的学习我们知道只要是将Bean放到了BeanDefinitionMap中那么就势必会经过Spring的那套Bean的生命周期就势必会创建Bean。2.1xml组件扫描方式首先我们在xml中是通过这段代码来进行组件扫描的扫描指定的基本包及其子包下的类识别使用Component注解context:component-scan base-packagecom.itheima/依据之前学习的命名空间的知识我们知道通过命名空间是可以找到它对应的Handler处理器的命名空间xmlns:contexthttp://www.springframework.org/schema/context对应的Handler处理器http\://www.springframework.org/schema/contextorg.springframework.context.config.ContextNamespaceHandlerhttp\://www.springframework.org/schema/jeeorg.springframework.ejb.config.JeeNamespaceHandlerhttp\://www.springframework.org/schema/langorg.springframework.scripting.config.LangNamespaceHandlerhttp\://www.springframework.org/schema/taskorg.springframework.scheduling.config.TaskNamespaceHandlerhttp\://www.springframework.org/schema/cacheorg.springframework.cache.config.CacheNamespaceHandler进入ContextNamespaceHandler//// Source code recreated from a .class file by IntelliJ IDEA// (powered by FernFlower decompiler)//packageorg.springframework.context.config;importorg.springframework.beans.factory.xml.NamespaceHandlerSupport;importorg.springframework.context.annotation.AnnotationConfigBeanDefinitionParser;importorg.springframework.context.annotation.ComponentScanBeanDefinitionParser;publicclassContextNamespaceHandlerextendsNamespaceHandlerSupport{publicContextNamespaceHandler(){}publicvoidinit(){this.registerBeanDefinitionParser(property-placeholder,newPropertyPlaceholderBeanDefinitionParser());this.registerBeanDefinitionParser(property-override,newPropertyOverrideBeanDefinitionParser());this.registerBeanDefinitionParser(annotation-config,newAnnotationConfigBeanDefinitionParser());this.registerBeanDefinitionParser(component-scan,newComponentScanBeanDefinitionParser());this.registerBeanDefinitionParser(load-time-weaver,newLoadTimeWeaverBeanDefinitionParser());this.registerBeanDefinitionParser(spring-configured,newSpringConfiguredBeanDefinitionParser());this.registerBeanDefinitionParser(mbean-export,newMBeanExportBeanDefinitionParser());this.registerBeanDefinitionParser(mbean-server,newMBeanServerBeanDefinitionParser());}}进入component-scan对应的ComponentScanBeanDefinitionParser看它的parse解析方法NullablepublicBeanDefinitionparse(Elementelement,ParserContextparserContext){StringbasePackageelement.getAttribute(base-package);basePackageparserContext.getReaderContext().getEnvironment().resolvePlaceholders(basePackage);String[]basePackagesStringUtils.tokenizeToStringArray(basePackage,,; \t\n);ClassPathBeanDefinitionScannerscannerthis.configureScanner(parserContext,element);SetBeanDefinitionHolderbeanDefinitionsscanner.doScan(basePackages);this.registerComponents(parserContext.getReaderContext(),beanDefinitions,element);returnnull;}进入ClassPathBeanDefinitionScanner的doScan方法重点看这if(this.checkCandidate(beanName,candidate)){BeanDefinitionHolderdefinitionHoldernewBeanDefinitionHolder(candidate,beanName);definitionHolderAnnotationConfigUtils.applyScopedProxyMode(scopeMetadata,definitionHolder,this.registry);beanDefinitions.add(definitionHolder);this.registerBeanDefinition(definitionHolder,this.registry);}执行到BeanDefinitionHolder definitionHolder new BeanDefinitionHolder(candidate, beanName);时可以看到BeanName是OtherBean3BeanDefinitionMap为空执行完this.registerBeanDefinition(definitionHolder, this.registry);OtherBean3就注入了BeanDefinitionMap由此可见xml组件扫描方式是将Bean直接放到BeanDefinitionMap中实现创建Bean的并没有通过BeanFactoryPostProcessor。2.2注解方式主键扫描首先先是进入AnnotationConfigApplicationContext类publicclassAnnotationConfigApplicationContextextendsGenericApplicationContextimplementsAnnotationConfigRegistry{privatefinalAnnotatedBeanDefinitionReaderreader;privatefinalClassPathBeanDefinitionScannerscanner;publicAnnotationConfigApplicationContext(){StartupStepcreateAnnotatedBeanDefReaderthis.getApplicationStartup().start(spring.context.annotated-bean-reader.create);this.readernewAnnotatedBeanDefinitionReader(this);createAnnotatedBeanDefReader.end();this.scannernewClassPathBeanDefinitionScanner(this);}publicAnnotationConfigApplicationContext(DefaultListableBeanFactorybeanFactory){super(beanFactory);this.readernewAnnotatedBeanDefinitionReader(this);this.scannernewClassPathBeanDefinitionScanner(this);}publicAnnotationConfigApplicationContext(Class?...componentClasses){this();this.register(componentClasses);this.refresh();}publicAnnotationConfigApplicationContext(String...basePackages){this();this.scan(basePackages);this.refresh();}直接进入this()publicAnnotationConfigApplicationContext(){StartupStepcreateAnnotatedBeanDefReaderthis.getApplicationStartup().start(spring.context.annotated-bean-reader.create);this.readernewAnnotatedBeanDefinitionReader(this);createAnnotatedBeanDefReader.end();this.scannernewClassPathBeanDefinitionScanner(this);}进入AnnotatedBeanDefinitionReader之前xml的形式是XmlBeanDefinitionReaderpublicAnnotatedBeanDefinitionReader(BeanDefinitionRegistryregistry){this(registry,getOrCreateEnvironment(registry));}publicAnnotatedBeanDefinitionReader(BeanDefinitionRegistryregistry,Environmentenvironment){this.beanNameGeneratorAnnotationBeanNameGenerator.INSTANCE;this.scopeMetadataResolvernewAnnotationScopeMetadataResolver();Assert.notNull(registry,BeanDefinitionRegistry must not be null);Assert.notNull(environment,Environment must not be null);this.registryregistry;this.conditionEvaluatornewConditionEvaluator(registry,environment,(ResourceLoader)null);AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);}再是进入**AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);**中的registerAnnotationConfigProcessorspublicstaticSetBeanDefinitionHolderregisterAnnotationConfigProcessors(BeanDefinitionRegistryregistry,NullableObjectsource){DefaultListableBeanFactorybeanFactoryunwrapDefaultListableBeanFactory(registry);if(beanFactory!null){if(!(beanFactory.getDependencyComparator()instanceofAnnotationAwareOrderComparator)){beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);}if(!(beanFactory.getAutowireCandidateResolver()instanceofContextAnnotationAutowireCandidateResolver)){beanFactory.setAutowireCandidateResolver(newContextAnnotationAutowireCandidateResolver());}}SetBeanDefinitionHolderbeanDefsnewLinkedHashSet(8);if(!registry.containsBeanDefinition(org.springframework.context.annotation.internalConfigurationAnnotationProcessor)){RootBeanDefinitiondefnewRootBeanDefinition(ConfigurationClassPostProcessor.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry,def,org.springframework.context.annotation.internalConfigurationAnnotationProcessor));}if(!registry.containsBeanDefinition(org.springframework.context.annotation.internalAutowiredAnnotationProcessor)){RootBeanDefinitiondefnewRootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry,def,org.springframework.context.annotation.internalAutowiredAnnotationProcessor));}if(jsr250Present!registry.containsBeanDefinition(org.springframework.context.annotation.internalCommonAnnotationProcessor)){RootBeanDefinitiondefnewRootBeanDefinition(CommonAnnotationBeanPostProcessor.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry,def,org.springframework.context.annotation.internalCommonAnnotationProcessor));}if(jpaPresent!registry.containsBeanDefinition(org.springframework.context.annotation.internalPersistenceAnnotationProcessor)){RootBeanDefinitiondefnewRootBeanDefinition();try{def.setBeanClass(ClassUtils.forName(org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor,AnnotationConfigUtils.class.getClassLoader()));}catch(ClassNotFoundExceptionex){thrownewIllegalStateException(Cannot load optional framework class: org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor,ex);}def.setSource(source);beanDefs.add(registerPostProcessor(registry,def,org.springframework.context.annotation.internalPersistenceAnnotationProcessor));}if(!registry.containsBeanDefinition(org.springframework.context.event.internalEventListenerProcessor)){RootBeanDefinitiondefnewRootBeanDefinition(EventListenerMethodProcessor.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry,def,org.springframework.context.event.internalEventListenerProcessor));}if(!registry.containsBeanDefinition(org.springframework.context.event.internalEventListenerFactory)){RootBeanDefinitiondefnewRootBeanDefinition(DefaultEventListenerFactory.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry,def,org.springframework.context.event.internalEventListenerFactory));}returnbeanDefs;}在这里会注册六个if中的Bean进入BeanDefinitionMap当中每执行完一次return beanDefs就是注册一个。再进入ConfigurationClassPostProcessor.class因为是注解形式的组件扫描看到postProcessBeanDefinitionRegistry中的parser.parse(candidates);的parse方法关注与parse相关的for(BeanDefinitionHolderholder:this.componentScanParser.parse(componentScan,sourceClass.getMetadata().getClassName())){继续推进看componentScanParser的parse方法ClassPathBeanDefinitionScannerscannernewClassPathBeanDefinitionScanner(this.registry,componentScan.getBoolean(useDefaultFilters),this.environment,this.resourceLoader);是否有一种似曾相识燕归来的感觉呢哈哈实际上这是和xml配置组件扫描是一致的啦接下来就是老套路了继续看doscan由此进入returnscanner.doScan(StringUtils.toStringArray(basePackages));if(this.checkCandidate(beanName,candidate)){BeanDefinitionHolderdefinitionHoldernewBeanDefinitionHolder(candidate,beanName);definitionHolderAnnotationConfigUtils.applyScopedProxyMode(scopeMetadata,definitionHolder,this.registry);beanDefinitions.add(definitionHolder);this.registerBeanDefinition(definitionHolder,this.registry);一样的逻辑定义definitionHolder使用BeanDefinitionRegistry的registerBeanDefinition(definitionHolder进行注册Bean到BeanDefinitionMap当中完结了。

相关新闻

计算机软件资格考试—Python补充

计算机软件资格考试—Python补充

创建一个范围在(0,1)之间的长度为12的等差数列:np.linspace(0, 1,12)Pandas 中,如果要查看某一列的数据类型,可以使用dtype方法。在Pandas 中如果要查看某一列数据的值(去除重复后的值),那么可以使用方法:unique()如果…

2026/5/17 4:56:31 阅读更多 →
一文讲透|AI论文软件 千笔写作工具 VS 知文AI,专为本科生量身打造!

一文讲透|AI论文软件 千笔写作工具 VS 知文AI,专为本科生量身打造!

随着人工智能技术的迅猛发展,AI辅助写作工具已经成为高校学生完成毕业论文的重要帮手。无论是开题报告、文献综述还是整篇论文的撰写,越来越多的学生开始借助AI工具提升效率、降低写作难度。然而,面对市场上琳琅满目的AI写作平台,…

2026/7/5 6:23:57 阅读更多 →
真心不骗你!继续教育必备的AI论文写作软件,千笔·专业论文写作工具 VS 云笔AI

真心不骗你!继续教育必备的AI论文写作软件,千笔·专业论文写作工具 VS 云笔AI

随着人工智能技术的迅猛发展,AI辅助写作工具已经逐步渗透到高校学术写作场景中,成为专科生、本科生、研究生完成毕业论文不可或缺的得力助手。越来越多的学生开始借助这些工具来简化写作流程、提升创作效率。然而,面对市场上种类繁多、功能各…

2026/7/5 0:39:51 阅读更多 →

最新新闻

MegaDepth环境配置与依赖安装:Python 2.7到3.x迁移完整解决方案

MegaDepth环境配置与依赖安装:Python 2.7到3.x迁移完整解决方案

MegaDepth环境配置与依赖安装:Python 2.7到3.x迁移完整解决方案 【免费下载链接】MegaDepth Code of single-view depth prediction algorithm on Internet Photos described in "MegaDepth: Learning Single-View Depth Prediction from Internet Photos, Z. …

2026/7/6 16:13:28 阅读更多 →
Real-ESRGAN实战指南:让模糊图片秒变高清的神奇AI工具

Real-ESRGAN实战指南:让模糊图片秒变高清的神奇AI工具

Real-ESRGAN实战指南:让模糊图片秒变高清的神奇AI工具 【免费下载链接】Real-ESRGAN Real-ESRGAN aims at developing Practical Algorithms for General Image/Video Restoration. 项目地址: https://gitcode.com/gh_mirrors/re/Real-ESRGAN 你是否曾经为模…

2026/7/6 16:13:28 阅读更多 →
终极Swift异步方案:AwaitKit中async/await关键字详解

终极Swift异步方案:AwaitKit中async/await关键字详解

终极Swift异步方案:AwaitKit中async/await关键字详解 【免费下载链接】AwaitKit The ES8 Async/Await control flow for Swift 项目地址: https://gitcode.com/gh_mirrors/aw/AwaitKit 还在为Swift异步编程的回调地狱而烦恼吗?😫 想要…

2026/7/6 16:11:25 阅读更多 →
揭秘BNB Smart Chain创世合约:10大核心组件工作原理与交互机制

揭秘BNB Smart Chain创世合约:10大核心组件工作原理与交互机制

揭秘BNB Smart Chain创世合约:10大核心组件工作原理与交互机制 【免费下载链接】bsc-genesis-contract The genesis contracts of BNB Smart Chain. 项目地址: https://gitcode.com/gh_mirrors/bs/bsc-genesis-contract BNB Smart Chain创世合约是BNB智能链生…

2026/7/6 16:11:25 阅读更多 →
mark-sweep垃圾收集器性能调优与基准测试终极指南

mark-sweep垃圾收集器性能调优与基准测试终极指南

mark-sweep垃圾收集器性能调优与基准测试终极指南 【免费下载链接】mark-sweep A simple mark-sweep garbage collector in C 项目地址: https://gitcode.com/gh_mirrors/ma/mark-sweep mark-sweep垃圾收集器作为最简单的垃圾回收算法之一,在内存管理和性能优…

2026/7/6 16:09:18 阅读更多 →
5步解锁加密视频:res-downloader让全网资源一键下载

5步解锁加密视频:res-downloader让全网资源一键下载

5步解锁加密视频:res-downloader让全网资源一键下载 【免费下载链接】res-downloader 视频号、小程序、抖音、快手、小红书、直播流、m3u8、酷狗、QQ音乐等常见网络资源下载! 项目地址: https://gitcode.com/GitHub_Trending/re/res-downloader 你是否经常遇…

2026/7/6 16:09:18 阅读更多 →

日新闻

H2 与 MySQL 单元测试兼容性:5 个关键 SQL 语句差异与规避方案

H2 与 MySQL 单元测试兼容性:5 个关键 SQL 语句差异与规避方案

H2与MySQL单元测试兼容性:5个关键SQL语句差异与规避方案1. 单元测试中的数据库兼容性挑战在Java开发领域,单元测试是保证代码质量的重要环节。当应用涉及数据库操作时,测试环境的搭建往往成为开发者的痛点。H2数据库因其轻量级、内存模式和快…

2026/7/6 0:01:17 阅读更多 →
Windows任务栏终极清理指南:用RBTray一键隐藏窗口到系统托盘

Windows任务栏终极清理指南:用RBTray一键隐藏窗口到系统托盘

Windows任务栏终极清理指南:用RBTray一键隐藏窗口到系统托盘 【免费下载链接】rbtray A fork of RBTray from http://sourceforge.net/p/rbtray/code/. 项目地址: https://gitcode.com/gh_mirrors/rb/rbtray 你是否厌倦了Windows任务栏上密密麻麻的图标&…

2026/7/6 0:01:17 阅读更多 →
Visual C++ 运行时库一键安装终极指南:告别DLL缺失烦恼

Visual C++ 运行时库一键安装终极指南:告别DLL缺失烦恼

Visual C 运行时库一键安装终极指南:告别DLL缺失烦恼 【免费下载链接】vcredist AIO Repack for latest Microsoft Visual C Redistributable Runtimes 项目地址: https://gitcode.com/gh_mirrors/vc/vcredist 你是否曾经遇到过这样的情况:下载了…

2026/7/6 0:05:19 阅读更多 →

周新闻

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容 【免费下载链接】BiliTools A cross-platform bilibili toolbox. 跨平台哔哩哔哩工具箱,支持下载视频、番剧等等各类资源 项目地址: https://gitcode.com/GitHub_Trending/bilit/BiliTools …

2026/7/6 8:11:50 阅读更多 →
威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型的陌生现状在忙碌疲惫的一天里,参与了关于混合后量子密码学的讨论,应付端点攻击找茬的人,还参与留言板讨论后,发现“威胁模型”对多数人仍是陌生概念,且多被当作时髦用语。有趣的相关画作有一幅由 Embyr 创作的…

2026/7/6 8:11:52 阅读更多 →
渗透测试入门指南:从零基础到实战环境搭建

渗透测试入门指南:从零基础到实战环境搭建

1. 从“看热闹”到“入门”:我理解的渗透测试到底是什么?每次看到新闻里说某个大公司的数据被“黑”了,或者某个网站被攻击导致服务瘫痪,你是不是和我一样,心里会冒出两个念头:一是“这黑客真厉害”&#x…

2026/7/6 6:52:56 阅读更多 →

月新闻