Spring源码解析之路 Bean加载篇

本文涉及的产品
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: Spring源码解析之路 Bean加载篇

前言

上面一章,说明了bena的解析与注册,这些都是未bean加载做的准备工作,真正复杂的还是bean的加载,但是通过前面的学习,我们也会清楚了各个类在spring容器的职责,这样就可能理解他们的使用,当我们进行扩展时就会更清晰明了,不会看到别人的代码一头雾水,比如下面这段代码的理解

/**
 * 注册bean
 */
public class RegisterBeanFactory implements BeanDefinitionRegistryPostProcessor {
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {

        // 注册bean  这里就是省略了解析,因为解析实际上就是构建BeanDefinition
        GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
        beanDefinition.setBeanClass(ProxyBeanFactory.class);
        BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(beanDefinition, "userDao");
        BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, registry);
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {

    }
}

上面的代码就是手动注册一个bean到容器中,如果看了之前的文章是不是就很明了了呢,现在我们来看看bean的加载

bean加载

从这段代码开始

    BeanFactory beanFactory = new ClassPathXmlApplicationContext("spring-config.xml");
    UserDao userDao = beanFactory.getBean("userDao", UserDao.class);

getbean方法就是加载的开始,真正的实现就是在AbstractBeanFactory类的doGetBean方法

 protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException {
        // 提取对应的beanName
        String beanName = this.transformedBeanName(name);
        // 检查缓存中或者实例工厂中是否有对应的实例
        // 原因是创建单例bean的时候会存在依赖注入的情况,而在创建依赖的时候为了避免循环依赖
        // Spring的解决方案是不等bean创建完成就会创建bean的ObjectFactory提早曝光
        // 就是将ObjectFactory加入缓存,一旦下一个bean创建时需要依赖上一个bean则直接使用缓存中bean'Factory
        // 直接尝试从缓存获取,或者singletonFactories的ObjectFactory获取
        Object sharedInstance = this.getSingleton(beanName);
        Object beanInstance;
        if (sharedInstance != null && args == null) {
            if (this.logger.isTraceEnabled()) {
                if (this.isSingletonCurrentlyInCreation(beanName)) {
                    this.logger.trace("Returning eagerly cached instance of singleton bean '" + beanName + "' that is not fully initialized yet - a consequence of a circular reference");
                } else {
                    this.logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
                }
            }

            beanInstance = this.getObjectForBeanInstance(sharedInstance, name, beanName, (RootBeanDefinition)null);
        } else {
            // 只有单例模式下才会尝试解决循环依赖,原型模式下如果存在依赖,那么就会抛出异常
            if (this.isPrototypeCurrentlyInCreation(beanName)) {
                throw new BeanCurrentlyInCreationException(beanName);
            }
            
            BeanFactory parentBeanFactory = this.getParentBeanFactory();
            // 如果beanDefitionMap找不到beanName则会尝试从parentBeanFactory中找
            if (parentBeanFactory != null && !this.containsBeanDefinition(beanName)) {
                String nameToLookup = this.originalBeanName(name);
                if (parentBeanFactory instanceof AbstractBeanFactory) {
                    return ((AbstractBeanFactory)parentBeanFactory).doGetBean(nameToLookup, requiredType, args, typeCheckOnly);
                }

                if (args != null) {
                    return parentBeanFactory.getBean(nameToLookup, args);
                }

                if (requiredType != null) {
                    return parentBeanFactory.getBean(nameToLookup, requiredType);
                }

                return parentBeanFactory.getBean(nameToLookup);
            }

            if (!typeCheckOnly) {
                this.markBeanAsCreated(beanName);
            }

            StartupStep beanCreation = this.applicationStartup.start("spring.beans.instantiate").tag("beanName", name);

            try {
                if (requiredType != null) {
                    beanCreation.tag("beanType", requiredType::toString);
                }
                // 将GenericBeanDefinition转换为RootBeanDefinition,如果指定的bean是子bean那么会合并父bean信息
                RootBeanDefinition mbd = this.getMergedLocalBeanDefinition(beanName);
                this.checkMergedBeanDefinition(mbd, beanName, args);
                
                String[] dependsOn = mbd.getDependsOn();
                String[] var12;
                // 如存在依赖,就要递归实现依赖的bean
                if (dependsOn != null) {
                    var12 = dependsOn;
                    int var13 = dependsOn.length;

                    for(int var14 = 0; var14 < var13; ++var14) {
                        String dep = var12[var14];
                        if (this.isDependent(beanName, dep)) {
                            throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
                        }
                        // 缓存以来调用
                        this.registerDependentBean(dep, beanName);

                        try {
                            this.getBean(dep);
                        } catch (NoSuchBeanDefinitionException var31) {
                            throw new BeanCreationException(mbd.getResourceDescription(), beanName, "'" + beanName + "' depends on missing bean '" + dep + "'", var31);
                        }
                    }
                }
                // 实例化依赖的bean后,就开始实例化mbd本身,这个有意思,之前的理解都是本身先实例化
                // 单例模式的创建
                if (mbd.isSingleton()) {
                    sharedInstance = this.getSingleton(beanName, () -> {
                        try {
                            return this.createBean(beanName, mbd, args);
                        } catch (BeansException var5) {
                            this.destroySingleton(beanName);
                            throw var5;
                        }
                    });
                    beanInstance = this.getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
                } else if (mbd.isPrototype()) {
                    // 原型模式创建
                    var12 = null;

                    Object prototypeInstance;
                    try {
                        this.beforePrototypeCreation(beanName);
                        prototypeInstance = this.createBean(beanName, mbd, args);
                    } finally {
                        this.afterPrototypeCreation(beanName);
                    }

                    beanInstance = this.getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
                } else {
                    String scopeName = mbd.getScope();
                    if (!StringUtils.hasLength(scopeName)) {
                        throw new IllegalStateException("No scope name defined for bean ��" + beanName + "'");
                    }

                    Scope scope = (Scope)this.scopes.get(scopeName);
                    if (scope == null) {
                        throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
                    }

                    try {
                        Object scopedInstance = scope.get(beanName, () -> {
                            this.beforePrototypeCreation(beanName);

                            Object var4;
                            try {
                                var4 = this.createBean(beanName, mbd, args);
                            } finally {
                                this.afterPrototypeCreation(beanName);
                            }

                            return var4;
                        });
                        beanInstance = this.getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
                    } catch (IllegalStateException var30) {
                        throw new ScopeNotActiveException(beanName, scopeName, var30);
                    }
                }
            } catch (BeansException var32) {
                beanCreation.tag("exception", var32.getClass().toString());
                beanCreation.tag("message", String.valueOf(var32.getMessage()));
                this.cleanupAfterBeanCreationFailure(beanName);
                throw var32;
            } finally {
                beanCreation.end();
            }
        }

        return this.adaptBeanInstance(name, beanInstance, requiredType);
    }

以上代码就是spring加载bean的过程,下面我们来一步步分析一下

  1. 转换对应的beanName

    这部分对应的就是transformedBeanName方法

          /**
          *返回实际的 bean 名称,去掉工厂引用 * 前缀(如果有,也去掉重复的工厂前缀,如果找到)。                 * @param name bean 的名称 * @return 转换后的名称 * @see *BeanFactory#FACTORY_BEAN_PREFIX
           */
          public static String transformedBeanName(String name) {
                  Assert.notNull(name, "'name' must not be null");
                  if (!name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
                          return name;
                  }
                  return transformedBeanNameCache.computeIfAbsent(name, beanName -> {
                          do {
                                  beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
                          }
                          while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
                          return beanName;
                  });
          }
    
      

    既然我们之间解析和注册的时候已经明确了beanName那么为什么还要转换呢,从这个方法的注释我们可以知道,beanName有可能有前缀如&,那么这样就要把他去掉,另外我们定义bean的时候可能会用到alias别名,这里的别名就要进行转换,比如别名A指向beanB,那么别名A要返回beanB

  2. 尝试从缓存中加载依赖

    这部分主要是为了解决循环依赖,单例的情况下,解决依赖的方式就是,在spring bean还没加载完,就将他里面的对象先放到缓存中ObjectFactory,读取的时候如果缓存里面有就从缓存里面读取,如果没有就从singletonFactories中读取。

  3. bean的实例化

    这一步时我们可能有一个疑问,bean不是已经在解析和注册时已经实例化到缓存BeanDefinitionResitry中了吗?为什么还要再实例化,那是因为解析和注册后我们得到的是初始状态的bean,而我们真正需要的bean是facoty-mthod返回的bean,他的创建是由getObjectForBeanInstance方法来完成的

  4. 原型模式下判断循环依赖

    spring会对循环依赖处理都是在单例模式下,如果原型模式出现了这种情况会直接抛出异常

  5. 检测parentBeanFactory

    如果当前的缓存中没有找到beanName的配置,那么就去parentBeanFactory中查找,找到后再通过递归调用getBean方法。

  6. 存储xml文件的GernericBeanDefinition转换为RootBeanDefinition

    spring的后续处理都是针对RootBeanDefinition进行处理的,所以我们要把解析后的GernericBeanDefinition转换成RootBeanDefinition

  7. 寻找依赖

    spring bean的创建过程中,要先创建bean中的属性,比如depends-on="jedisPoolConfig"

     <!-- jedis pool配置 -->
     <bean id="jedisPool" class="redis.clients.jedis.JedisPool" destroy-method="destroy" depends-on="jedisPoolConfig">
      <constructor-arg ref="jedisPoolConfig" />  
      <constructor-arg value="127.0.0.1" />  
      <constructor-arg type="int" value="6379" />  
     </bean>
    

depends-on="jedisPoolConfig" 在实例话前加载

  1. 针对不同的scope进行加载

    singleton,prototype,request多种scope

获取单例bean

从前面的代码中了解到,单例在spring容器只会创建一次,后续都是从缓存或者singletonFactoty中获取,为了解决循环依赖,spring会在不等bean创建完成就将创建bena的beanFactory提早曝光,下面看看他的实现
getSingleton方法

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
                Assert.notNull(beanName, "Bean name must not be null");
                // 锁定全局变量并进行处理
                synchronized (this.singletonObjects) {
                        // 缓存中是否存在实例
                        Object singletonObject = this.singletonObjects.get(beanName);
                        if (singletonObject == null) {
                              
                                if (this.singletonsCurrentlyInDestruction) {
                                        throw new BeanCreationNotAllowedException(beanName,
                                                        "Singleton bean creation not allowed while singletons of this factory are in destruction " +
                                                        "(Do not request a bean from a BeanFactory in a destroy method implementation!)");
                                }
                                if (logger.isDebugEnabled()) {
                                        logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
                                }
                                beforeSingletonCreation(beanName);
                                boolean newSingleton = false;
                                boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
                                if (recordSuppressedExceptions) {
                                        this.suppressedExceptions = new LinkedHashSet<>();
                                }
                                try {   
                                        // 调用预先设定的getObjct方法
                                        singletonObject = singletonFactory.getObject();
                                        newSingleton = true;
                                }
                                catch (IllegalStateException ex) {
                                        // Has the singleton object implicitly appeared in the meantime ->
                                        // if yes, proceed with it since the exception indicates that state.
                                        singletonObject = this.singletonObjects.get(beanName);
                                        if (singletonObject == null) {
                                                throw ex;
                                        }
                                }
                                catch (BeanCreationException ex) {
                                        if (recordSuppressedExceptions) {
                                                for (Exception suppressedException : this.suppressedExceptions) {
                                                        ex.addRelatedCause(suppressedException);
                                                }
                                        }
                                        throw ex;
                                }
                                finally {
                                        if (recordSuppressedExceptions) {
                                                this.suppressedExceptions = null;
                                        }
                                        afterSingletonCreation(beanName);
                                }
                                if (newSingleton) {
                                        // 记录到缓存中
                                        addSingleton(beanName, singletonObject);
                                }
                        }
                        return singletonObject;
                }
}

从bean实例中获取对象

在这一步前面的过程分别是 解析-注册-从不同的scope中获取bean,那么这一步就是终极加载,前面的流程中获得的bean其实都是初始状态的bean,而这一步就是要在前面的基础上加料了,这一步对应的方法就是getObjectForBeanInstance方法

protected Object getObjectForBeanInstance(
                        Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {

                // 如果指定的name是工厂相关&前缀,且beanInstace又不是Factory则验证不通过
      
                if (BeanFactoryUtils.isFactoryDereference(name)) {
                        if (beanInstance instanceof NullBean) {
                                return beanInstance;
                        }
                        if (!(beanInstance instanceof FactoryBean)) {
                                throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
                        }
                        if (mbd != null) {
                                mbd.isFactoryBean = true;
                        }
                        return beanInstance;
                }

                // Now we have the bean instance, which may be a normal bean or a FactoryBean.
                // If it's a FactoryBean, we use it to create a bean instance, unless the
                // caller actually wants a reference to the factory.
                if (!(beanInstance instanceof FactoryBean)) {
                        return beanInstance;
                }

                Object object = null;
                if (mbd != null) {
                        mbd.isFactoryBean = true;
                }
                else {  
                        // 尝试从缓存中加载
                        object = getCachedObjectForFactoryBean(beanName);
                }
                if (object == null) {
                        // Return bean instance from factory. 明确知道beanInstance是Factory类型
                        FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
                        // Caches object obtained from FactoryBean if it is a singleton.
                        if (mbd == null && containsBeanDefinition(beanName)) {
                                // 父类合并
                                mbd = getMergedLocalBeanDefinition(beanName);
                        }
                        boolean synthetic = (mbd != null && mbd.isSynthetic());
                        object = getObjectFromFactoryBean(factory, beanName, !synthetic);
                }
                return object;
        }
        

主要工作就是

  • 对FactoryBean进行验证
  • 对非FactoryBean不做处理
  • 对bean进行转换
  • 最后委托给getObjectFromFactoryBean方法
         protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
                if (factory.isSingleton() && containsSingleton(beanName)) {
                        synchronized (getSingletonMutex()) {
                                Object object = this.factoryBeanObjectCache.get(beanName);
                                if (object == null) {
                                        object = doGetObjectFromFactoryBean(factory, beanName);
                                        // Only post-process and store if not put there already during getObject() call above
                                        // (e.g. because of circular reference processing triggered by custom getBean calls)
                                        Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
                                        if (alreadyThere != null) {
                                                object = alreadyThere;
                                        }
                                        else {
                                                if (shouldPostProcess) {
                                                        if (isSingletonCurrentlyInCreation(beanName)) {
                                                                // Temporarily return non-post-processed object, not storing it yet..
                                                                return object;
                                                        }
                                                        beforeSingletonCreation(beanName);
                                                        try {
                                                                object = postProcessObjectFromFactoryBean(object, beanName);
                                                        }
                                                        catch (Throwable ex) {
                                                                throw new BeanCreationException(beanName,
                                                                                "Post-processing of FactoryBean's singleton object failed", ex);
                                                        }
                                                        finally {
                                                                afterSingletonCreation(beanName);
                                                        }
                                                }
                                                if (containsSingleton(beanName)) {
                                                        this.factoryBeanObjectCache.put(beanName, object);
                                                }
                                        }
                                }
                                return object;
                        }
                }
                else {
                        // 这里面直接调动了FactotyBean的getObject方法
                        Object object = doGetObjectFromFactoryBean(factory, beanName);
                        if (shouldPostProcess) {
                                try {   
                                        // 调用ObjectFactory的后置处理器
                                        object = postProcessObjectFromFactoryBean(object, beanName);
                                }
                                catch (Throwable ex) {
                                        throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
                                }
                        }
                        return object;
                }
        }

从代码中可以看出,其实在加载完bean后又执行了一个调用后置处理器的操作,这个操作就是为了以后对spring加载bean的灵活拓展

@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
        throws BeansException {

    Object result = existingBean;
    for (BeanPostProcessor processor : getBeanPostProcessors()) {
        Object current = processor.postProcessAfterInitialization(result, beanName);
        if (current == null) {
            return result;
        }
        result = current;
    }
    return result;
}
相关文章
|
15天前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
45 2
|
2月前
|
搜索推荐 Java Spring
Spring Filter深度解析
【10月更文挑战第21天】Spring Filter 是 Spring 框架中非常重要的一部分,它为请求处理提供了灵活的控制和扩展机制。通过合理配置和使用 Filter,可以实现各种个性化的功能,提升应用的安全性、可靠性和性能。还可以结合具体的代码示例和实际应用案例,进一步深入探讨 Spring Filter 的具体应用和优化技巧,使对它的理解更加全面和深入。
|
22天前
|
缓存 Java Spring
实战指南:四种调整 Spring Bean 初始化顺序的方案
本文探讨了如何调整 Spring Boot 中 Bean 的初始化顺序,以满足业务需求。文章通过四种方案进行了详细分析: 1. **方案一 (@Order)**:通过 `@Order` 注解设置 Bean 的初始化顺序,但发现 `@PostConstruct` 会影响顺序。 2. **方案二 (SmartInitializingSingleton)**:在所有单例 Bean 初始化后执行额外的初始化工作,但无法精确控制特定 Bean 的顺序。 3. **方案三 (@DependsOn)**:通过 `@DependsOn` 注解指定 Bean 之间的依赖关系,成功实现顺序控制,但耦合性较高。
实战指南:四种调整 Spring Bean 初始化顺序的方案
|
2月前
|
Java 测试技术 Windows
咦!Spring容器里为什么没有我需要的Bean?
【10月更文挑战第11天】项目经理给小菜分配了一个紧急需求,小菜迅速搭建了一个SpringBoot项目并完成了开发。然而,启动测试时发现接口404,原因是控制器包不在默认扫描路径下。通过配置`@ComponentScan`的`basePackages`字段,解决了问题。总结:`@SpringBootApplication`默认只扫描当前包下的组件,需要扫描其他包时需配置`@ComponentScan`。
|
2月前
|
XML Java 数据格式
Spring IOC容器的深度解析及实战应用
【10月更文挑战第14天】在软件工程中,随着系统规模的扩大,对象间的依赖关系变得越来越复杂,这导致了系统的高耦合度,增加了开发和维护的难度。为解决这一问题,Michael Mattson在1996年提出了IOC(Inversion of Control,控制反转)理论,旨在降低对象间的耦合度,提高系统的灵活性和可维护性。Spring框架正是基于这一理论,通过IOC容器实现了对象间的依赖注入和生命周期管理。
73 0
|
2月前
|
缓存 Java 程序员
Map - LinkedHashSet&Map源码解析
Map - LinkedHashSet&Map源码解析
70 0
|
2月前
|
算法 Java 容器
Map - HashSet & HashMap 源码解析
Map - HashSet & HashMap 源码解析
57 0
|
2月前
|
存储 Java C++
Collection-PriorityQueue源码解析
Collection-PriorityQueue源码解析
62 0
|
2月前
|
安全 Java 程序员
Collection-Stack&Queue源码解析
Collection-Stack&Queue源码解析
85 0
|
16天前
|
存储 安全 Linux
Golang的GMP调度模型与源码解析
【11月更文挑战第11天】GMP 调度模型是 Go 语言运行时系统的核心部分,用于高效管理和调度大量协程(goroutine)。它通过少量的操作系统线程(M)和逻辑处理器(P)来调度大量的轻量级协程(G),从而实现高性能的并发处理。GMP 模型通过本地队列和全局队列来减少锁竞争,提高调度效率。在 Go 源码中,`runtime.h` 文件定义了关键数据结构,`schedule()` 和 `findrunnable()` 函数实现了核心调度逻辑。通过深入研究 GMP 模型,可以更好地理解 Go 语言的并发机制。

推荐镜像

更多