千家信息网

Bean的解析与注册是怎样的

发表于:2026-11-02 作者:千家信息网编辑
千家信息网最后更新 2026年11月02日,本篇文章为大家展示了Bean的解析与注册是怎样的,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。我们将一起探讨spring对bean解析,并注册到IOC容器的过
千家信息网最后更新 2026年11月02日Bean的解析与注册是怎样的

本篇文章为大家展示了Bean的解析与注册是怎样的,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。

我们将一起探讨spring对bean解析,并注册到IOC容器的过程。

我们先接着看下面这段代码:

ClassPathBeanDefinitionScanner类

//类路径Bean定义扫描器扫描给定包及其子包        protected Set doScan(String... basePackages) {                Assert.notEmpty(basePackages, "At least one base package must be specified");                //创建一个集合,存放扫描到的BeanDefinition封装类                Set beanDefinitions = new LinkedHashSet<>();                //遍历扫描所有给定的包路径                for (String basePackage : basePackages) {                        //调用父类ClassPathScanningCandidateComponentProvider的方法                        //扫描给定类路径,获取符合条件的Bean定义10                      Set candidates = findCandidateComponents(basePackage);                        //遍历扫描到的Bean                        for (BeanDefinition candidate : candidates) {                                //获取@Scope注解的值,即获取Bean的作用域14                              ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);                                //为Bean设置作用域                                candidate.setScope(scopeMetadata.getScopeName());                                //为Bean生成名称18                              String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);                                //如果扫描到的Bean不是Spring的注解Bean,则为Bean设置默认值,                                //设置Bean的自动依赖注入装配属性等                                if (candidate instanceof AbstractBeanDefinition) {                                        postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);                                }                                //如果扫描到的Bean是Spring的注解Bean,则处理其通用的Spring注解                                if (candidate instanceof AnnotatedBeanDefinition) {                                        //处理注解Bean中通用的注解,在分析注解Bean定义类读取器时已经分析过                                        AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);                                }                                //根据Bean名称检查指定的Bean是否需要在容器中注册,或者在容器中冲突30                              if (checkCandidate(beanName, candidate)) {                                        BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);                                        //根据注解中配置的作用域,为Bean应用相应的代理模式33                                      definitionHolder =                                                        AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);                                        beanDefinitions.add(definitionHolder);                                        //向容器注册扫描到的Bean37                                      registerBeanDefinition(definitionHolder, this.registry);                                }                        }                }                return beanDefinitions;        }

上篇文章我们主要分析了第10行的 findCandidateComponents(basePackage)方法, 该方法主要是从给定的包路径中扫描符合过滤规则的Bean,并存入集合beanDefinitions中。
接下来的步骤可以分为以下几个方面:

  • 遍历bean集合

  • 获取@Scope注解的值,即获取Bean的作用域

  • 为Bean生成名称

  • 给Bean的一些属性设置默认值

  • 检查Bean是否已在IOC容器中注册

  • 根据Bean的作用域,生成相应的代理模式

  • 把Bean放入IOC容器中

第二步、获取@Scope注解的值,即获取Bean的作用域

首先来看下 获取Bean作用域的过程,主要是上面第14行ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);这段代码,我们继续跟踪进去:
AnnotationScopeMetadataResolver类

public ScopeMetadata resolveScopeMetadata(BeanDefinition definition) {                //默认是singleton                ScopeMetadata metadata = new ScopeMetadata();                if (definition instanceof AnnotatedBeanDefinition) {                        AnnotatedBeanDefinition annDef = (AnnotatedBeanDefinition) definition;                        //获取@Scope注解的值                        AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(                                        annDef.getMetadata(), this.scopeAnnotationType);                        //将获取到的@Scope注解的值设置到要返回的对象中                        if (attributes != null) {                                metadata.setScopeName(attributes.getString("value"));                                //获取@Scope注解中的proxyMode属性值,在创建代理对象时会用到                                ScopedProxyMode proxyMode = attributes.getEnum("proxyMode");                                //如果@Scope的proxyMode属性为DEFAULT或者NO                                if (proxyMode == ScopedProxyMode.DEFAULT) {                                        //设置proxyMode为NO                                        proxyMode = this.defaultProxyMode;                                }                                //为返回的元数据设置proxyMode                                metadata.setScopedProxyMode(proxyMode);                        }                }                //返回解析的作用域元信息对象                return metadata;        }

Bean的作用域是通过@Scope注解实现的,我们先来看下@Scope注解的属性:


可以看到@Scope注解有三个属性,

  • value属性就是我们常用的用来设置Bean的单例/多例

  • proxyMode是用来设置代理方式的

关于@Scope注解原理的详细分析,请看这篇文章<>,这里就不详细讲了。

这里的AnnotationAttributes是注解属性key-value的封装类,继承了LinkedHashMap,所以也是key-value形式的数据结构。 通过debug看一下,这个变量拿到的值:


可以看到获取到了3个属性的值,其中value = prototype就是该Bean的作用域,这里我设置的是多例,然后再把获取到的注解属性值赋值给ScopeMetadata。

第三步、为Bean生成名称

再回到上面ClassPathBeanDefinitionScanner类的doScan()方法中的第18行, 把我们获取到的Bean的作用域赋值给Bean。
然后为Bean生成名字,代码String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
跟踪进去,在AnnotationBeanNameGenerator类中:

public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {                if (definition instanceof AnnotatedBeanDefinition) {                        String beanName = determineBeanNameFromAnnotation((AnnotatedBeanDefinition) definition);                        if (StringUtils.hasText(beanName)) {                                // Explicit bean name found.                                return beanName;                        }                }                // Fallback: generate a unique default bean name.                return buildDefaultBeanName(definition, registry);        }

这段代码很好理解,先从注解中获取Bean的名称,如果注解中没有设置,那么生成一个默认的Bean的名称,通过ClassUtils.getShortName(beanClassName)生成一个类名的小写开头驼峰的名字,如studentController。

第四步、给Bean的一些属性设置默认值

主要是doScan()中的如下两个方法:

//如果扫描到的Bean不是Spring的注解Bean,则为Bean设置默认值,                                //设置Bean的自动依赖注入装配属性等                                if (candidate instanceof AbstractBeanDefinition) {                                        postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);                                }                                //如果扫描到的Bean是Spring的注解Bean,则处理其通用的Spring注解                                if (candidate instanceof AnnotatedBeanDefinition) {                                        //处理注解Bean中通用的注解,在分析注解Bean定义类读取器时已经分析过                                        AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);                                }

首先看postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName):
跟踪进去会到如下方法:

public void applyDefaults(BeanDefinitionDefaults defaults) {                //懒加载                setLazyInit(defaults.isLazyInit());                //加载模式                setAutowireMode(defaults.getAutowireMode());                //依赖检查                setDependencyCheck(defaults.getDependencyCheck());                //bean初始化方法                setInitMethodName(defaults.getInitMethodName());                setEnforceInitMethod(false);                //bean销毁方法                setDestroyMethodName(defaults.getDestroyMethodName());                setEnforceDestroyMethod(false);        }

这里应该很清晰了,给bean设置一些默认值,BeanDefinitionDefaults是一个Bean属性默认值的封装类,从该类获取各个属性的默认值,赋值给bean。
接着我们看AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate)方法。
跟踪进去:

static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd, AnnotatedTypeMetadata metadata) {                AnnotationAttributes lazy = attributesFor(metadata, Lazy.class);                //如果Bean定义中有@Lazy注解,则将该Bean预实例化属性设置为@lazy注解的值                if (lazy != null) {                        abd.setLazyInit(lazy.getBoolean("value"));                }                else if (abd.getMetadata() != metadata) {                        lazy = attributesFor(abd.getMetadata(), Lazy.class);                        if (lazy != null) {                                abd.setLazyInit(lazy.getBoolean("value"));                        }                }                //如果Bean定义中有@Primary注解,则为该Bean设置为autowiring自动依赖注入装配的首选对象                if (metadata.isAnnotated(Primary.class.getName())) {                        abd.setPrimary(true);                }                //如果Bean定义中有@ DependsOn注解,则为该Bean设置所依赖的Bean名称,                //容器将确保在实例化该Bean之前首先实例化所依赖的Bean                AnnotationAttributes dependsOn = attributesFor(metadata, DependsOn.class);                if (dependsOn != null) {                        abd.setDependsOn(dependsOn.getStringArray("value"));                }                if (abd instanceof AbstractBeanDefinition) {                        AbstractBeanDefinition absBd = (AbstractBeanDefinition) abd;                        AnnotationAttributes role = attributesFor(metadata, Role.class);                        if (role != null) {                                absBd.setRole(role.getNumber("value").intValue());                        }                        AnnotationAttributes description = attributesFor(metadata, Description.class);                        if (description != null) {                                absBd.setDescription(description.getString("value"));                        }                }        }

这里主要是处理bean上一些常用的注解,如@Lazy、@Primary、@DependsOn。
注释很清晰,这里就不赘言了。

第五步、检查Bean是否已在IOC容器中注册

跟踪doScan()中的第30行if (checkCandidate(beanName, candidate))方法:

protected boolean checkCandidate(String beanName, BeanDefinition beanDefinition) throws IllegalStateException {                //是否包含beanName了                if (!this.registry.containsBeanDefinition(beanName)) {                        return true;                }                //如果容器中已经存在同名bean                //获取容器中已存在的bean                BeanDefinition existingDef = this.registry.getBeanDefinition(beanName);                BeanDefinition originatingDef = existingDef.getOriginatingBeanDefinition();                if (originatingDef != null) {                        existingDef = originatingDef;                }                //新bean旧bean进行比较                if (isCompatible(beanDefinition, existingDef)) {                        return false;                }                throw new ConflictingBeanDefinitionException("Annotation-specified bean name '" + beanName +                                "' for bean class [" + beanDefinition.getBeanClassName() + "] conflicts with existing, " +                                "non-compatible bean definition of same name and class [" + existingDef.getBeanClassName() + "]");        }

可以看到,其实是通过调用IOC容器的containsBeanDefinition(beanName)方法,来判断该beanName是否已存在,而IOC容器实际上是一个map,这里底层其实就是通过调用map.containsKey(key)来实现的。

第六步、为Bean应用相应的代理模式

跟踪doScan()中的 definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);方法

static BeanDefinitionHolder applyScopedProxyMode(                        ScopeMetadata metadata, BeanDefinitionHolder definition, BeanDefinitionRegistry registry) {                //获取注解Bean定义类中@Scope注解的proxyMode属性值                ScopedProxyMode scopedProxyMode = metadata.getScopedProxyMode();                //如果配置的@Scope注解的proxyMode属性值为NO,则不应用代理模式                if (scopedProxyMode.equals(ScopedProxyMode.NO)) {                        return definition;                }                //获取配置的@Scope注解的proxyMode属性值,如果为TARGET_CLASS                //则返回true,如果为INTERFACES,则返回false                boolean proxyTargetClass = scopedProxyMode.equals(ScopedProxyMode.TARGET_CLASS);                //为注册的Bean创建相应模式的代理对象                return ScopedProxyCreator.createScopedProxy(definition, registry, proxyTargetClass);        }

这里就用到第二步中我门获取到的@Scope注解的proxyMode属性,然后为bean设置代理模式。

第七步、注册Bean到IOC容器中

跟踪doScan()中的第37行registerBeanDefinition(definitionHolder, this.registry);方法

//将解析的BeanDefinitionHold注册到容器中        public static void registerBeanDefinition(                        BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)                        throws BeanDefinitionStoreException {                // Register bean definition under primary name.                //获取解析的BeanDefinition的名称                String beanName = definitionHolder.getBeanName();                //向IOC容器注册BeanDefinition第9行             registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());                // Register aliases for bean name, if any.                //如果解析的BeanDefinition有别名,向容器为其注册别名                String[] aliases = definitionHolder.getAliases();                if (aliases != null) {                        for (String alias : aliases) {                                registry.registerAlias(beanName, alias);                        }                }        }

直接看第9行的代码,继续跟踪进去:

//向IOC容器注册解析的BeanDefiniton        @Override        public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)                        throws BeanDefinitionStoreException {                // 校验 beanName 与 beanDefinition 非空                Assert.hasText(beanName, "Bean name must not be empty");                Assert.notNull(beanDefinition, "BeanDefinition must not be null");                //校验解析的BeanDefiniton                if (beanDefinition instanceof AbstractBeanDefinition) {                        try {                                ((AbstractBeanDefinition) beanDefinition).validate();                        }                        catch (BeanDefinitionValidationException ex) {                                throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,                                                "Validation of bean definition failed", ex);                        }                }                BeanDefinition oldBeanDefinition;                // 从容器中获取指定 beanName 的 BeanDefinition                oldBeanDefinition = this.beanDefinitionMap.get(beanName);                // 如果已经存在                if (oldBeanDefinition != null) {                        // 如果存在但是不允许覆盖,抛出异常                        if (!isAllowBeanDefinitionOverriding()) {                                throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,                                                "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +                                                "': There is already [" + oldBeanDefinition + "] bound.");                        }                        // 覆盖 beanDefinition 大于 被覆盖的 beanDefinition 的 ROLE ,打印 info 日志                        else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {                                // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE                                if (this.logger.isWarnEnabled()) {                                        this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +                                                        "' with a framework-generated bean definition: replacing [" +                                                        oldBeanDefinition + "] with [" + beanDefinition + "]");                                }                        }                        else if (!beanDefinition.equals(oldBeanDefinition)) {                                if (this.logger.isInfoEnabled()) {                                        this.logger.info("Overriding bean definition for bean '" + beanName +                                                        "' with a different definition: replacing [" + oldBeanDefinition +                                                        "] with [" + beanDefinition + "]");                                }                        }                        else {                                if (this.logger.isDebugEnabled()) {                                        this.logger.debug("Overriding bean definition for bean '" + beanName +                                                        "' with an equivalent definition: replacing [" + oldBeanDefinition +                                                        "] with [" + beanDefinition + "]");                                }                        }                        // 允许覆盖,直接覆盖原有的 BeanDefinition 到 beanDefinitionMap 中。                        this.beanDefinitionMap.put(beanName, beanDefinition);                }                else {                        // 检测创建 Bean 阶段是否已经开启,如果开启了则需要对 beanDefinitionMap 进行并发控制                        if (hasBeanCreationStarted()) {                                // Cannot modify startup-time collection elements anymore (for stable iteration)                                //注册的过程中需要线程同步,以保证数据的一致性(因为有put、add、remove操作)64                              synchronized (this.beanDefinitionMap) {                                        this.beanDefinitionMap.put(beanName, beanDefinition);                                        List updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);                                        updatedDefinitions.addAll(this.beanDefinitionNames);                                        updatedDefinitions.add(beanName);                                        this.beanDefinitionNames = updatedDefinitions;                                        // 从 manualSingletonNames 移除 beanName                                        if (this.manualSingletonNames.contains(beanName)) {                                                Set updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);                                                updatedSingletons.remove(beanName);                                                this.manualSingletonNames = updatedSingletons;                                        }                                }                        }                        else {                                // Still in startup registration phase                                this.beanDefinitionMap.put(beanName, beanDefinition);                                this.beanDefinitionNames.add(beanName);                                this.manualSingletonNames.remove(beanName);                        }                        this.frozenBeanDefinitionNames = null;                }                //检查是否有同名的BeanDefinition已经在IOC容器中注册88              if (oldBeanDefinition != null || containsSingleton(beanName)) {                        //更新beanDefinitionNames 和 manualSingletonNames                        resetBeanDefinition(beanName);                }        }

这里就是向IOC容器中注册bean的核心代码,这段代码很长,我们分开来看,主要分为几个步骤:

  • beanName和beanDefinition的合法性校验

  • 根据beanName从IOC容器中判断是否已经注册过
    根据isAllowBeanDefinitionOverriding变量来判断是否覆盖

  • 如果存在根据覆盖规则,执行覆盖或者抛出异常

  • 如果不存在,则put到IOC容器beanDefinitionMap中
    private final Map beanDefinitionMap = new ConcurrentHashMap<>(256);

到这里,注册bean到IOC容器的过程就基本结束了,实际上IOC注册不是什么神秘的东西,说白了就是把beanName和bean存入map集合中

此时我们再返回看第七步的代码BeanDefinitionReaderUtils类的registerBeanDefinition()方法,可以看到 registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());我们已经分析完了,剩下的就是把bean的别名也注册进去就大功告成了。

//将解析的BeanDefinitionHold注册到容器中        public static void registerBeanDefinition(                        BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)                        throws BeanDefinitionStoreException {                // Register bean definition under primary name.                //获取解析的BeanDefinition的名称                String beanName = definitionHolder.getBeanName();                //向IOC容器注册BeanDefinition                registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());                // Register aliases for bean name, if any.                //如果解析的BeanDefinition有别名,向容器为其注册别名                String[] aliases = definitionHolder.getAliases();                if (aliases != null) {                        for (String alias : aliases) {                                registry.registerAlias(beanName, alias);                        }                }        }
总结:

IoC容器其实就是DefaultListableBeanFactory,它里面有一个map类型的beanDefinitionMap变量,来存储注册的bean

IoC容器初始化过程:

  • 1、资源定位
    扫描包路径下.class文件,将资源转为Resource

  • 2、资源加载
    通过ASM框架获取class元数据,封装到BeanDefinition

  • 3、资源解析
    获取bean上注解的属性值。如@Scope

  • 4、生成Bean
    生成beanName,设置Bean默认值(懒加载、初始化方法等)、代理模式

  • 5、注册Bean
    把BeanDefinition放入IoC容器DefaultListableBeanFactory

最后思考几个小疑问:

  • beanDefinitionMap是ConcurrentHashMap类型的,应该是线程安全的,但是为什么在代码64行的地方,还要加sync锁呢?

  • 之前已经检查过容器中是否有重名bean了,为什么在88行还要再检查一次呢?

上述内容就是Bean的解析与注册是怎样的,你们学到知识或技能了吗?如果还想学到更多技能或者丰富自己的知识储备,欢迎关注行业资讯频道。

0