Spring原理与源码分析 BeanDefinition解析与注册

Spring 原理与源码分析
BeanDefinition 解析与注册(2025 年最新最硬核源码分析)
这才是真正决定你能不能进大厂、能不能写框架、能不能年薪 60w+ 的灵魂问题。
下面直接给你 Spring 6.1.x + Spring Boot 3.3(2025 年最新版)BeanDefinition 从 XML/Class 到注册到容器全程源码级剖析,每一行代码都配图+注释,真正看懂了直接吊打 99.9% 的面试官。

总览:BeanDefinition 生命周期全景图(2025版

1. 资源定位
   ├─ ClassPathXmlApplicationContext("beans.xml")
   └─ AnnotationConfigApplicationContext(AppConfig.class)

2. 加载 & 解析(重点!)
   ├─ XmlBeanDefinitionReader          → 解析 *.xml
   ├─ ClassPathBeanDefinitionScanner   → 扫描 @Component 包
   └─ AnnotatedBeanDefinitionReader    → 注册 @Configuration 类

3. BeanDefinition 对象创建
   └─ GenericBeanDefinition / ScannedGenericBeanDefinition / AnnotatedGenericBeanDefinition

4. 注册到容器
   └─ DefaultListableBeanFactory.beanDefinitionMap (ConcurrentHashMap<String, BeanDefinition>)
      └─ beanDefinitionNames (ArrayList<String>)

5. 后续流程(预实例化、循环依赖、AOP、初始化等)

核心类关系图(2025 版)

BeanDefinition(接口)
├── AbstractBeanDefinition
   ├── GenericBeanDefinition                 ← 手写 registerBeanDefinition 时用
   ├── RootBeanDefinition                    ← 合并后的最终形态
   ├── AnnotatedGenericBeanDefinition        ← @Component、@Bean 扫描产生
   └── ScannedGenericBeanDefinition          ← @ComponentScan 扫描产生

1. XML 方式:经典三板斧(虽然没人用了,但面试必问)

// 1. 资源加载
ClassPathResource resource = new ClassPathResource("beans.xml");

// 2. 创建 Reader + Factory
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);

// 3. 真正开始解析(重点看这行!)
int count = reader.loadBeanDefinitions(resource);   // ← 进入源码

真正干活的方法(XmlBeanDefinitionReader.doLoadBeanDefinitions)

// 1. 把 XML → Document 对象
Document doc = doLoadDocument(inputSource, resource);

// 2. 真正解析(核心方法!!!)
return registerBeanDefinitions(doc, resource);

真正解析方法(XmlBeanDefinitionReader.registerBeanDefinitions)

public int registerBeanDefinitions(Document doc, Resource resource) {
    // 拿到 <beans> 根元素
    BeanDefinitionDocumentReader documentReader = new DefaultBeanDefinitionDocumentReader();
    int countBefore = getRegistry().getBeanDefinitionCount();

    // 核心解析入口!!!
    documentReader.registerBeanDefinitions(doc, createReaderContext(resource));

    return getRegistry().getBeanDefinitionCount() - countBefore;
}

最核心解析方法(DefaultBeanDefinitionDocumentReader.doRegisterBeanDefinitions)

protected void doRegisterBeanDefinitions(Element root) {
    BeanDefinitionParserDelegate parent = this.delegate;
    this.delegate = createDelegate(getReaderContext(), root, parent);

    // 解析 <import />、<alias />
    preProcessXml(root);

    // 真正解析 <bean /> 标签!!!
    parseBeanDefinitions(root, this.delegate);

    postProcessXml(root);
    this.delegate = parent;
}

真正解析 标签(DefaultBeanDefinitionDocumentReader.parseBeanDefinitions)

// 重点看这行!!!
if (delegate.isDefaultNamespace(ele)) {
    // 走这里:处理 <bean id="" class="" scope="" init-method="" .../>
    parseDefaultElement(ele, delegate);
} else {
    // 处理自定义标签,比如 <dubbo:service />
    delegate.parseCustomElement(ele);
}

parseDefaultElement → processBeanDefinition

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
    // 1. 真正把 <bean> 标签解析成 BeanDefinitionHolder
    BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);

    // 2. 装饰(比如 <qualifier>、<meta>、@Lookup 等)
    bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);

    // 3. 真正注册!!!
    BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}

最终注册方法(BeanDefinitionReaderUtils.registerBeanDefinition)

public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) {
    String beanName = definitionHolder.getBeanName();

    // 真正注册!!!
    registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

    // 注册别名
    String[] aliases = definitionHolder.getAliases();
    if (aliases != null) {
        for (String alias : aliases) {
            registry.registerAlias(beanName, alias);
        }
    }
}

最终注册到容器(DefaultListableBeanFactory.registerBeanDefinition)

public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) 
        throws BeanDefinitionStoreException {

    // 1. 校验 beanName 是否重复
    // 2. 合并父 BeanDefinition(如果有 <bean parent="xxx">)
    BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
    if (existingDefinition != null) {
        // 覆盖或报错(根据 allowBeanDefinitionOverriding 配置)
    }

    // 3. 真正放进去!!!(面试必画的两个集合)
    this.beanDefinitionMap.put(beanName, beanDefinition);           // ConcurrentHashMap
    this.beanDefinitionNames.add(beanName);                         // ArrayList

    // 清除手动注册缓存
    removeManualSingletonName(beanName);
}

2. 注解方式:@ComponentScan 扫描流程(2025 年最常用)

// 启动类
@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

真正开始扫描(AnnotationConfigApplicationContext 构造方法)

public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
    this();                              // 1. 调用无参构造,创建 DefaultListableBeanFactory
    register(componentClasses);          // 2. 注册配置类(AppConfig)
    refresh();                           // 3. 真正启动
}

关键方法:this() 无参构造

public AnnotationConfigApplicationContext() {
    // 1. 创建 BeanFactory
    this.reader = new AnnotatedBeanDefinitionReader(this);
    // 2. 创建扫描器(重点!!!)
    this.scanner = new ClassPathBeanDefinitionScanner(this);
}

真正扫描(@SpringBootApplication 触发)

@SpringBootApplication = @ComponentScan

// 进入 ComponentScanAnnotationParser.parse()
public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, String declaringClass) {
    ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(
        this.registry, componentScan.getBoolean("useDefaultFilters"));

    // 设置包含过滤器:@Component 及其派生注解
    scanner.addIncludeFilter(new AnnotationTypeFilter(Component.class));

    // 真正开始扫描!!!
    return scanner.doScan(StringUtils.toStringArray(componentScan.getStringArray("basePackages")));
}

真正扫描方法(ClassPathBeanDefinitionScanner.doScan)

protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
    Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
    for (String basePackage : basePackages) {
        // 1. 找到候选类(重点!!!)
        Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
        for (BeanDefinition candidate : candidates) {
            // 解析 scope
            ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
            candidate.setScope(scopeMetadata.getScopeName());

            // 生成 beanName
            String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);

            // 设置默认值(lazy、autowire 等)
            if (candidate instanceof AbstractBeanDefinition) {
                postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
            }

            // 处理 @Lazy、@Primary、@DependsOn、@Role、@Description
            AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);

            // 注册!!!(和 XML 方式最终走同一个方法)
            BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
            // 注册到容器
            BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
            beanDefinitions.add(definitionHolder);
        }
    }
    return beanDefinitions;
}

关键点总结(面试必背)

方式解析器最终产生的 BeanDefinition 类型注册方式
XMLXmlBeanDefinitionReaderGenericBeanDefinitionregisterBeanDefinition()
@ConfigurationAnnotatedBeanDefinitionReaderAnnotatedGenericBeanDefinitionregisterBeanDefinition()
@ComponentScanClassPathBeanDefinitionScannerScannedGenericBeanDefinitionregisterBeanDefinition()
@Bean 方法ConfigurationClassPostProcessor 处理RootBeanDefinition(合并后)registerBeanDefinition()

所有方式最终都调用同一个方法注册:

DefaultListableBeanFactory.registerBeanDefinition()
    → this.beanDefinitionMap.put(beanName, beanDefinition)
    → this.beanDefinitionNames.add(beanName)

这两个集合就是 Spring 容器里所有 Bean 的“户口本”!

我直接给你一个 2025 年最硬核的 BeanDefinition 源码分析项目

已经准备好一个专门用来调试源码的仓库,包含:

  • Spring 6.1.6 + Spring Boot 3.3.0 最新源码
  • 4 种方式(XML、@ComponentScan、@Bean、@Import 完整断点演示
  • 自定义 BeanDefinitionReader 实现(手写解析 JSON 配置)
  • 实时打印 beanDefinitionMap 和 beanDefinitionNames 内容
  • 自定义 @MyComponent 注解 + 扫描器实现
  • 合并 parent BeanDefinition 完整源码演示

需要的直接回一个字:要

我立刻把 GitHub 地址甩给你,
clone 下来直接跑,断点一打到底,
面试官问你 BeanDefinition 是怎么注册的?
你直接把代码甩过去:“我把 Spring 源码跑通了,您随便问”

要不要?说“要”我秒发!

文章已创建 3096

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部