springboot 自动装配
一般我们启动一个项目只需要再启动类上面增加@SpringBootApplication
注解,就能自动的装备bean对象,原理是什么呢? 下面从
SpringApplication.run()
开始进行解析一下
从上图中我们很容易就进入到了SpringApplication.run()
方法中, 注意我上述框起来的两行代码分别是创建上下文和刷新上下文
创建上下文 this.createApplicationContext
从上述源码中,我们可以知道spring 通过反射的方式创建了一个Context
, 可以根据WebApplicationType
创建指定的上下文, 这里以AnnotationConfigServletWebServerApplicationContext
为例子,进入源码
AnnotationConfigServletWebServerApplicationContext
在这个上下文中,可以看到这里创建了两个对象, 一个是根据注解的Reader
和 根据路径的Scanner
,并且传入了自身的上下文引用
从上面两图中,我们可以看见帮助可上下文注册了BeanFactory
的后置处理器, 比如框住的部分就是增加了ConfigurationClassPostProcessor
后置处理器
更新上下文this.refreshContext(context)
在更新上下文的时候,最终会进入到AbstractApplicationContext
的refresh
方法中,如下图所示
invokeBeanFactoryPostProcessors
invokeBeanFactoryPostProcessors
是一个BeanFactory
类型的后置处理方法,在该方法获取所有注册的BeanFactoryPostProcessor
,并且执行postProcessBeanFactory
方法,代码如下图
// AbstractApplicationContext# invokeBeanFactoryPostProcessors
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, this.getBeanFactoryPostProcessors());
.......
}
// PostProcessorRegistrationDelegate# invokeBeanFactoryPostProcessors
public static void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
.......
invokeBeanFactoryPostProcessors((Collection)nonOrderedPostProcessors, (ConfigurableListableBeanFactory)beanFactory);
.......
}
// PostProcessorRegistrationDelegate# invokeBeanFactoryPostProcessors
private static void invokeBeanFactoryPostProcessors(Collection<? extends BeanFactoryPostProcessor> postProcessors, ConfigurableListableBeanFactory beanFactory) {
Iterator var2 = postProcessors.iterator();
while(var2.hasNext()) {
BeanFactoryPostProcessor postProcessor = (BeanFactoryPostProcessor)var2.next();
postProcessor.postProcessBeanFactory(beanFactory);
}
}
如上图代码所示, 最终会执行BeanFactoryPostProcessor.postProcessBeanFactory
, 还记得在创建上下文中我们最后一张图,我们注册了一些BeanFactoryPostProcessor
吗? 就以ConfigurationClassPostProcessor
为例,在执行postProcessBeanFactory
时,进入该方法,最后调用processConfigBeanDefinitions
进行解析和注册BeanDefinitions
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
.... 省略
if (!this.registriesPostProcessed.contains(factoryId)) {
this.processConfigBeanDefinitions((BeanDefinitionRegistry)beanFactory);
}
}
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
......
Set<BeanDefinitionHolder> candidates = new LinkedHashSet(configCandidates);
HashSet alreadyParsed = new HashSet(configCandidates.size());
do {
// 解析
parser.parse(candidates);
Set<ConfigurationClass> configClasses = new LinkedHashSet(parser.getConfigurationClasses());
.....
....
// 注册
this.reader.loadBeanDefinitions(configClasses);
...
}
}
在进入parse()
方法,实际上是进入到ConfigurationClassParser.parse
ConfigurationClassParser.parse
public void parse(Set<BeanDefinitionHolder> configCandidates) {
this.deferredImportSelectors = new LinkedList<>();
for (BeanDefinitionHolder holder : configCandidates) {
BeanDefinition bd = holder.getBeanDefinition();
try {
if (bd instanceof AnnotatedBeanDefinition) {
// 对于每个有注解的类,都执行方法parse(AnnotationMetadata metadata, String beanName)
parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
}
...
catch (BeanDefinitionStoreException ex) {
...
}
}
//后续处理DeferredImportSelector的实现类
processDeferredImportSelectors();
}
protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
processConfigurationClass(new ConfigurationClass(metadata, beanName));
}
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
.... 省略
do {
sourceClass = doProcessConfigurationClass(configClass, sourceClass);
}
while (sourceClass != null);
.... 省略
ConfigurationClassParser.doProcessConfigurationClass
经过多次调用,最终调用了doProcessConfigurationClass
方法,在该方法中针对不同的注解类型, 执行了不同的注解执行方法,比如针对启动类中@ComponentScan
注解, 这里会直接执行,扫描指定包下面对象并封装成BeanDefinitionHolder
,还有一个需要关注的是@Import 装配processImports
方法
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
// 执行 @PropertySource 注解
for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
....
}
// Process any @ComponentScan annotations
Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
if (!componentScans.isEmpty() &&
!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
for (AnnotationAttributes componentScan : componentScans) {
// 配置类使用 @ComponentScan 注解 -> 立即执行扫描
Set<BeanDefinitionHolder> scannedBeanDefinitions =
this.componentScanParser.parse(componentScan,sourceClass.getMetadata().getClassName());
// Check the set of scanned definitions for any further config classes and parse recursively if needed
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
if (bdCand == null) {
bdCand = holder.getBeanDefinition();
}
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
}
// 执行 @Import 注解
processImports(configClass, sourceClass, getImports(sourceClass), true);
// 执行 @ImportResource 注解
AnnotationAttributes importResource =
AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
if (importResource != null) {
String[] resources = importResource.getStringArray("locations");
Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
for (String resource : resources) {
String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
configClass.addImportedResource(resolvedResource, readerClass);
}
}
// 处理 @Bean methods
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
// 处理接口中的默认方法
processInterfaces(configClass, sourceClass);
// 执行父类,如果存在
if (sourceClass.getMetadata().hasSuperClass()) {
String superclass = sourceClass.getMetadata().getSuperClassName();
if (superclass != null && !superclass.startsWith("java") &&
!this.knownSuperclasses.containsKey(superclass)) {
this.knownSuperclasses.put(superclass, configClass);
// Superclass found, return its annotation metadata and recurse
return sourceClass.getSuperClass();
}
}
// No superclass -> processing is complete
return null;
}
ConfigurationClassParser.processImports
这里省略了其他代码,只留下关键代码selector.selectImports
, 在@EnableAutoConfiguration
注解中, @Import({AutoConfigurationImportSelector.class})
有这么一个注解, 因此,这里selector.selectImports
调用的实际上是AutoConfigurationImportSelector.selectImports
方法
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
Collection<SourceClass> importCandidates, boolean checkForCircularImports) {
...... 省略其他代码
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
...... 省略其他代码
}
AutoConfigurationImportSelector.selectImports
在进入到selectImports
后,调用了getCandidateConfigurations
,最终调用到了SpringFactoriesLoader.loadSpringFactories
方法
SpringFactoriesLoader.loadSpringFactories
根据代码我们可以发现, 最终类加载器会从META-INF/spring.factories
中获取所有全类限定名,便可提供给上层方法进行获取,最后创建对应的BeanDefinition
对象,在后面Bean的实例化过程中,便可实现自动装配了
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南