当前位置: 首页 > news >正文

Spring组件扫描原理解析

Spring组件扫描原理解析

一、概述

用一幅图来对两种方式配置Bean的组件扫描进行一个总结:

二、原理剖析

通过之前的学习我们知道只要是将Bean放到了BeanDefinitionMap中,那么就势必会经过Spring的那套Bean的生命周期,就势必会创建Bean。

2.1xml组件扫描方式

首先我们在xml中是通过这段代码来进行组件扫描的,扫描指定的基本包及其子包下的类,识别使用@Component注解:

<context:component-scan base-package="com.itheima"/>

依据之前学习的命名空间的知识我们知道,通过命名空间是可以找到它对应的Handler处理器的,命名空间:

xmlns:context="http://www.springframework.org/schema/context"

对应的Handler处理器:

http\://www.springframework.org/schema/context=org.springframework.context.config.ContextNamespaceHandlerhttp\://www.springframework.org/schema/jee=org.springframework.ejb.config.JeeNamespaceHandlerhttp\://www.springframework.org/schema/lang=org.springframework.scripting.config.LangNamespaceHandlerhttp\://www.springframework.org/schema/task=org.springframework.scheduling.config.TaskNamespaceHandlerhttp\://www.springframework.org/schema/cache=org.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){StringbasePackage=element.getAttribute("base-package");basePackage=parserContext.getReaderContext().getEnvironment().resolvePlaceholders(basePackage);String[]basePackages=StringUtils.tokenizeToStringArray(basePackage,",; \t\n");ClassPathBeanDefinitionScannerscanner=this.configureScanner(parserContext,element);Set<BeanDefinitionHolder>beanDefinitions=scanner.doScan(basePackages);this.registerComponents(parserContext.getReaderContext(),beanDefinitions,element);returnnull;}

进入ClassPathBeanDefinitionScanner的doScan方法,重点看这:

if(this.checkCandidate(beanName,candidate)){BeanDefinitionHolderdefinitionHolder=newBeanDefinitionHolder(candidate,beanName);definitionHolder=AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata,definitionHolder,this.registry);beanDefinitions.add(definitionHolder);this.registerBeanDefinition(definitionHolder,this.registry);}

执行到BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);时可以看到BeanName是OtherBean3,BeanDefinitionMap为空;执行完this.registerBeanDefinition(definitionHolder, this.registry);,OtherBean3就注入了BeanDefinitionMap:

由此可见xml组件扫描方式是将Bean直接放到BeanDefinitionMap中实现创建Bean的,并没有通过BeanFactoryPostProcessor。

2.2注解方式主键扫描

首先先是进入AnnotationConfigApplicationContext类:

publicclassAnnotationConfigApplicationContextextendsGenericApplicationContextimplementsAnnotationConfigRegistry{privatefinalAnnotatedBeanDefinitionReaderreader;privatefinalClassPathBeanDefinitionScannerscanner;publicAnnotationConfigApplicationContext(){StartupStepcreateAnnotatedBeanDefReader=this.getApplicationStartup().start("spring.context.annotated-bean-reader.create");this.reader=newAnnotatedBeanDefinitionReader(this);createAnnotatedBeanDefReader.end();this.scanner=newClassPathBeanDefinitionScanner(this);}publicAnnotationConfigApplicationContext(DefaultListableBeanFactorybeanFactory){super(beanFactory);this.reader=newAnnotatedBeanDefinitionReader(this);this.scanner=newClassPathBeanDefinitionScanner(this);}publicAnnotationConfigApplicationContext(Class<?>...componentClasses){this();this.register(componentClasses);this.refresh();}publicAnnotationConfigApplicationContext(String...basePackages){this();this.scan(basePackages);this.refresh();}

直接进入this(),

publicAnnotationConfigApplicationContext(){StartupStepcreateAnnotatedBeanDefReader=this.getApplicationStartup().start("spring.context.annotated-bean-reader.create");this.reader=newAnnotatedBeanDefinitionReader(this);createAnnotatedBeanDefReader.end();this.scanner=newClassPathBeanDefinitionScanner(this);}

进入AnnotatedBeanDefinitionReader,之前xml的形式是XmlBeanDefinitionReader:

publicAnnotatedBeanDefinitionReader(BeanDefinitionRegistryregistry){this(registry,getOrCreateEnvironment(registry));}publicAnnotatedBeanDefinitionReader(BeanDefinitionRegistryregistry,Environmentenvironment){this.beanNameGenerator=AnnotationBeanNameGenerator.INSTANCE;this.scopeMetadataResolver=newAnnotationScopeMetadataResolver();Assert.notNull(registry,"BeanDefinitionRegistry must not be null");Assert.notNull(environment,"Environment must not be null");this.registry=registry;this.conditionEvaluator=newConditionEvaluator(registry,environment,(ResourceLoader)null);AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);}

再是进入**AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);**中的registerAnnotationConfigProcessors:

publicstaticSet<BeanDefinitionHolder>registerAnnotationConfigProcessors(BeanDefinitionRegistryregistry,@NullableObjectsource){DefaultListableBeanFactorybeanFactory=unwrapDefaultListableBeanFactory(registry);if(beanFactory!=null){if(!(beanFactory.getDependencyComparator()instanceofAnnotationAwareOrderComparator)){beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);}if(!(beanFactory.getAutowireCandidateResolver()instanceofContextAnnotationAutowireCandidateResolver)){beanFactory.setAutowireCandidateResolver(newContextAnnotationAutowireCandidateResolver());}}Set<BeanDefinitionHolder>beanDefs=newLinkedHashSet(8);if(!registry.containsBeanDefinition("org.springframework.context.annotation.internalConfigurationAnnotationProcessor")){RootBeanDefinitiondef=newRootBeanDefinition(ConfigurationClassPostProcessor.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry,def,"org.springframework.context.annotation.internalConfigurationAnnotationProcessor"));}if(!registry.containsBeanDefinition("org.springframework.context.annotation.internalAutowiredAnnotationProcessor")){RootBeanDefinitiondef=newRootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry,def,"org.springframework.context.annotation.internalAutowiredAnnotationProcessor"));}if(jsr250Present&&!registry.containsBeanDefinition("org.springframework.context.annotation.internalCommonAnnotationProcessor")){RootBeanDefinitiondef=newRootBeanDefinition(CommonAnnotationBeanPostProcessor.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry,def,"org.springframework.context.annotation.internalCommonAnnotationProcessor"));}if(jpaPresent&&!registry.containsBeanDefinition("org.springframework.context.annotation.internalPersistenceAnnotationProcessor")){RootBeanDefinitiondef=newRootBeanDefinition();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")){RootBeanDefinitiondef=newRootBeanDefinition(EventListenerMethodProcessor.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry,def,"org.springframework.context.event.internalEventListenerProcessor"));}if(!registry.containsBeanDefinition("org.springframework.context.event.internalEventListenerFactory")){RootBeanDefinitiondef=newRootBeanDefinition(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方法:

ClassPathBeanDefinitionScannerscanner=newClassPathBeanDefinitionScanner(this.registry,componentScan.getBoolean("useDefaultFilters"),this.environment,this.resourceLoader);

是否有一种似曾相识燕归来的感觉呢?哈哈,实际上这是和xml配置组件扫描是一致的啦,接下来就是老套路了,继续看doscan,由此进入:

returnscanner.doScan(StringUtils.toStringArray(basePackages));
if(this.checkCandidate(beanName,candidate)){BeanDefinitionHolderdefinitionHolder=newBeanDefinitionHolder(candidate,beanName);definitionHolder=AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata,definitionHolder,this.registry);beanDefinitions.add(definitionHolder);this.registerBeanDefinition(definitionHolder,this.registry);

一样的逻辑定义definitionHolder,使用BeanDefinitionRegistry的registerBeanDefinition(definitionHolder进行注册Bean到BeanDefinitionMap当中,完结了。

http://www.jsqmd.com/news/384404/

相关文章:

  • 2026年推荐上海网站推广/上海网站建设行业参考推荐公司 - 品牌宣传支持者
  • 2026年比较好的无添加海鲜干货/海鲜干货鱿鱼干热门必买清单 - 品牌宣传支持者
  • 2026年质量好的汽车用品硅胶包胶/奶瓶硅胶包胶优质厂商精选推荐(口碑) - 品牌宣传支持者
  • 2026年靠谱的苏州网站设计/苏州做网站企业服务推荐公司 - 品牌宣传支持者
  • 基于西门子 S7 - 200 PLC 齿轮研磨专用机床的液压系统及液压缸设计探索
  • 从此告别拖延,AI论文网站 千笔·专业论文写作工具 VS 文途AI
  • 计算机软件资格考试—Python补充
  • 2026年比较好的轨道交通座椅调角器/扶手调角器行业内口碑厂家推荐 - 品牌宣传支持者
  • 一文讲透|AI论文软件 千笔写作工具 VS 知文AI,专为本科生量身打造!
  • 2026年热门的有氧呼吸面罩/医用呼吸面罩热门厂家推荐汇总 - 品牌宣传支持者
  • 真心不骗你!继续教育必备的AI论文写作软件,千笔·专业论文写作工具 VS 云笔AI
  • 深入解析:全栈之道:React 与 Next.js 的圆融觉醒
  • 2026年口碑好的封边聚氨酯保温板/岩棉聚氨酯保温板厂家热卖产品推荐(近期) - 品牌宣传支持者
  • 2026年比较好的输送带检测技术/井下输送带检测口碑排行精选供应商推荐 - 品牌宣传支持者
  • 2026年比较好的伺服冲床/电机伺服冲床厂家推荐参考 - 品牌宣传支持者
  • 2026年评价高的大气除氧器/低位除氧器人气实力厂商推荐 - 品牌宣传支持者
  • Claude Skill:给 AI 准备一份“工作交接文档“,它就能变专家
  • 校车管理信息|基于springboot + vue校车管理信息系统(源码+数据库+文档)
  • 2026年口碑好的H型高速冲床/C型高速冲床厂家采购参考指南 - 品牌宣传支持者
  • NocoBase 2.0 正式版发布
  • 2026年评价高的抗震铠装缝/地坪铠装缝厂家信誉综合参考 - 品牌宣传支持者
  • 2026年比较好的内墙变形缝/承重变形缝全方位厂家推荐参考 - 品牌宣传支持者
  • 2026年口碑好的小孔消音器/管道消音器厂家选购完整指南 - 品牌宣传支持者
  • 2026年质量好的进口喷码机/颜料喷码机厂家推荐与采购指南 - 品牌宣传支持者
  • 加油站管理系统|基于java + vue加油站管理系统(源码+数据库+文档)
  • 智慧博物馆预约系统|基于springboot + vue智慧博物馆预约系统(源码+数据库+文档)
  • 2026年靠谱的视觉激光打标机/手持激光打标机用户口碑认可厂家 - 品牌宣传支持者
  • 2026年热门的精密平面磨床/平面磨床热门品牌厂家推荐 - 品牌宣传支持者
  • 建议收藏|10个AI论文写作软件深度测评:继续教育毕业论文与科研写作必备工具
  • 这可能是程序员离用AI赚钱最容易的一个机会了