Spring原理学习系列之五:IOC原理之Bean加载

简介: 其实很多同学都想通过阅读框架的源码以汲取框架设计思想以及编程营养,Spring框架其实就是个很好的框架源码学习对象。我们都知道Bean是Spring框架的最小操作单元,Spring框架通过对于Bean的统一管理实现其IOC以及AOP等核心的框架功能,那么Spring框架是如何把Bean加载到环境中来进行管理的呢?本文将围绕这个话题进行详细的阐述,并配合Spring框架的源码解析。

引言

其实很多同学都想通过阅读框架的源码以汲取框架设计思想以及编程营养,Spring框架其实就是个很好的框架源码学习对象。我们都知道BeanSpring框架的最小操作单元,Spring框架通过对于Bean的统一管理实现其IOC以及AOP等核心的框架功能,那么Spring框架是如何把Bean加载到环境中来进行管理的呢?本文将围绕这个话题进行详细的阐述,并配合Spring框架的源码解析。

  • Bean创建
  • Bean加载流程
  • 总结


一、Bean创建

在搞清楚Spring框架如何加载Bean之前,我们需要明确Spring框架中的Bean是如何被创建的。那我们就不得不谈到BeanFactory。本文采用的AnnotationConfigApplicationContext来进行代码示例说明,它的类继承与实现结构如下所示。由图可知,BeanFactory是作为顶级接口的形式存在。

image.png

示例代码如下:

public class SpringTest {
    public static void main(String[] args) {
        ApplicationContext ac = new AnnotationConfigApplicationContext(UserServiceImpl.class);
        IUserService userService = (UserServiceImpl)ac.getBean("userService");
        //3.执行bean中的方法
        userService.query();
    }
}

如示例代码所示,在new AnnotationConfigApplicationContext(UserService.class)创建context过程中,实际调用了AnnotationConfigApplicationContext的构造方法,其重载的构造方法如下所示:

public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry {
...
  public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
    this();
    register(annotatedClasses);
    refresh();
  }
...
}

该构造方法主要完成三件事情:

1、this():初始化bean读取器以及扫描器,对应AnnotationConfigApplicationContext的无参构造函数,如下代码:

public AnnotationConfigApplicationContext() {
    //在IOC容器中初始化一个 注解bean读取器AnnotatedBeanDefinitionReader
    this.reader = new AnnotatedBeanDefinitionReader(this);
    //在IOC容器中初始化一个 按类路径扫描注解bean的扫描器
    this.scanner = new ClassPathBeanDefinitionScanner(this);
  }

2、register(annotatedClasses):进行Bean配置类注册,如下代码:

public void register(Class... annotatedClasses) {
        Assert.notEmpty(annotatedClasses, "At least one annotated class must be specified");
        this.reader.register(annotatedClasses);
    }

AnnotationConfigApplicationContext上下文中,通过AnnotatedBeanDefinitionReader调用register进行注解Bean的读取与注册操作。

public void register(Class<?>... annotatedClasses) {
    for (Class<?> annotatedClass : annotatedClasses) {
      registerBean(annotatedClass);
    }
  }
public void registerBean(Class<?> annotatedClass) {
    doRegisterBean(annotatedClass, null, null, null);
  }
<T> void doRegisterBean(Class<T> annotatedClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name,
      @Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) {
    //将注解类的数据格式转换为Bean容器中的AnnotatedGenericBeanDefinition
    AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
    //@Conditional装配条件判断是否需要跳过注册
    if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
      return;
    }
    //设置回调
    abd.setInstanceSupplier(instanceSupplier);
     //解析bean作用域(单例或者原型),如果有@Scope注解,则解析@Scope,没有则默认为singleton 
    ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
    //作用域写回BeanDefinition数据结构, abd中缺损的情况下为空,将默认值singleton重新赋值到abd
    abd.setScope(scopeMetadata.getScopeName());
    //生成bean配置类beanName
    String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
    //通用注解解析到abd结构中,主要是处理Lazy, primary DependsOn, Role ,Description这五个注解
    AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
    // @Qualifier特殊限定符处理
    if (qualifiers != null) {
      for (Class<? extends Annotation> qualifier : qualifiers) {
        if (Primary.class == qualifier) {
        // 如果配置@Primary注解,则设置当前Bean为自动装配autowire时首选bean 
          abd.setPrimary(true);
        }
        else if (Lazy.class == qualifier) {
        //设置当前bean为延迟加载
          abd.setLazyInit(true);
        }
        else {
          abd.addQualifier(new AutowireCandidateQualifier(qualifier));
        }
      }
    }
    for (BeanDefinitionCustomizer customizer : definitionCustomizers) {
      customizer.customize(abd);
    }
    BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
    definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
    //按照名称将对应的bean注册到IOC容器中(在下一篇文章中进行介绍)
    BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
  }

3、refresh():作用为刷新Spring的应用上下文;

刷新上下文的操作实际上是在AbstractApplicationContext中完成的。

public abstract class AbstractApplicationContext extends DefaultResourceLoader
    implements ConfigurableApplicationContext {
    ...
  @Override
  public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
      // 准备上下文环境
      prepareRefresh();
      // 创建并初始化BeanFactory(这部分可以继续追踪,创建BeanFactory的过程)
      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
      // 填充BeanFactory功能
      prepareBeanFactory(beanFactory);
      try {
        // 提供子类覆盖的额外处理,即子类处理自定义的BeanFactoryPostProcess
        postProcessBeanFactory(beanFactory);
        // 激活各种BeanFactory处理器
        invokeBeanFactoryPostProcessors(beanFactory);
         // 注册拦截Bean创建的Bean处理器,即注册 BeanPostProcessor
        registerBeanPostProcessors(beanFactory);
         // 初始化上下文中的资源文件,如国际化文件的处理等
        initMessageSource();
        // 初始化上下文事件广播器
        initApplicationEventMulticaster();
         // 给子类扩展初始化其他Bean
        onRefresh();
        // 在所有bean中查找listener bean,然后注册到广播器中
        registerListeners();
        // 初始化剩下的单例Bean(非延迟加载的)
        finishBeanFactoryInitialization(beanFactory);
        // 完成刷新过程,通知生命周期处理器lifecycleProcessor刷新过程,同时发出ContextRefreshEvent通知别人
        finishRefresh();
      }
      catch (BeansException ex) {
        if (logger.isWarnEnabled()) {
          logger.warn("Exception encountered during context initialization - " +
              "cancelling refresh attempt: " + ex);
        }
        //销毁已经创建的Bean
        destroyBeans();
        //重置容器激活标签
        cancelRefresh(ex);
        // 异常抛出
        throw ex;
      }
      finally {
        // Reset common introspection caches in Spring's core, since we
        // might not ever need metadata for singleton beans anymore...
        resetCommonCaches();
      }
    }
  }
  ...

image.png

二、Bean加载

image.png

(图片来自于网络)

AnnotationConfigApplicationContext继承了AbstractApplicationContext

ublic abstract class AbstractApplicationContext extends DefaultResourceLoader
    implements ConfigurableApplicationContext {
    ...
    @Override
    public Object getBean(String name) throws BeansException {
      assertBeanFactoryActive();
      return getBeanFactory().getBean(name);
  }
    ...
}

BeanFactory接口主要的实现是在AbstractBeanFactory中完成,doGetBean接收以下四个参数:

(1)name:准备获取 bean 的名字

(2)requiredType:准备获取 bean 的类型

(3)args:创建 bean 时传递的参数。这个参数仅限于创建 bean 时使用

(4)typeCheckOnly:是否为类型检查

public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {
...
  @Override
  public Object getBean(String name) throws BeansException {
    return doGetBean(name, null, null, false);
  }
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
      @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
    //转换Bean名称
    final String beanName = transformedBeanName(name);
    Object bean;
    // 从缓存中或者实例工厂中获取 bean
    Object sharedInstance = getSingleton(beanName);
    if (sharedInstance != null && args == null) {
      if (logger.isTraceEnabled()) {
        if (isSingletonCurrentlyInCreation(beanName)) {
          logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
              "' that is not fully initialized yet - a consequence of a circular reference");
        }
        else {
          logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
        }
      }
      bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
    }
    else {
      // Fail if we're already creating this bean instance:
      // We're assumably within a circular reference.
      if (isPrototypeCurrentlyInCreation(beanName)) {
        throw new BeanCurrentlyInCreationException(beanName);
      }
      // 如果容器中没有找到,则从父类容器中加载
      BeanFactory parentBeanFactory = getParentBeanFactory();
      if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
        // Not found -> check parent.
        String nameToLookup = originalBeanName(name);
        if (parentBeanFactory instanceof AbstractBeanFactory) {
          return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
              nameToLookup, requiredType, args, typeCheckOnly);
        }
        else if (args != null) {
          // Delegation to parent with explicit args.
          return (T) parentBeanFactory.getBean(nameToLookup, args);
        }
        else if (requiredType != null) {
          // No args -> delegate to standard getBean method.
          return parentBeanFactory.getBean(nameToLookup, requiredType);
        }
        else {
          return (T) parentBeanFactory.getBean(nameToLookup);
        }
      }
      if (!typeCheckOnly) {
        markBeanAsCreated(beanName);
      }
      try {
        final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
        checkMergedBeanDefinition(mbd, beanName, args);
        // 获取依赖的 Bean
        String[] dependsOn = mbd.getDependsOn();
        if (dependsOn != null) {
          for (String dep : dependsOn) {
            if (isDependent(beanName, dep)) {
              throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                  "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
            }
            registerDependentBean(dep, beanName);
            try {
              getBean(dep);
            }
            catch (NoSuchBeanDefinitionException ex) {
              throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                  "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
            }
          }
        }
        // 开始创建 Bean 实例,如果是单例的,那么会创建一个单例的匿名工厂,如果是原型模式的,则不需要创建单例的工厂的,其他的如 request、session 作用域的,则根据自身的需要
        if (mbd.isSingleton()) {
          sharedInstance = getSingleton(beanName, () -> {
            try {
              return createBean(beanName, mbd, args);
            }
            catch (BeansException ex) {
              // Explicitly remove instance from singleton cache: It might have been put there
              // eagerly by the creation process, to allow for circular reference resolution.
              // Also remove any beans that received a temporary reference to the bean.
              destroySingleton(beanName);
              throw ex;
            }
          });
          bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
        }
        else if (mbd.isPrototype()) {
          // It's a prototype -> create a new instance.
          Object prototypeInstance = null;
          try {
            beforePrototypeCreation(beanName);
            prototypeInstance = createBean(beanName, mbd, args);
          }
          finally {
            afterPrototypeCreation(beanName);
          }
          bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
        }
        else {
          String scopeName = mbd.getScope();
          final 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, () -> {
              beforePrototypeCreation(beanName);
              try {
                return createBean(beanName, mbd, args);
              }
              finally {
                afterPrototypeCreation(beanName);
              }
            });
            bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
          }
          catch (IllegalStateException ex) {
            throw new BeanCreationException(beanName,
                "Scope '" + scopeName + "' is not active for the current thread; consider " +
                "defining a scoped proxy for this bean if you intend to refer to it from a singleton",
                ex);
          }
        }
      }
      catch (BeansException ex) {
        cleanupAfterBeanCreationFailure(beanName);
        throw ex;
      }
    }
    // 类型检查,如果不能进行类型转换,则抛出异常
    if (requiredType != null && !requiredType.isInstance(bean)) {
      try {
        T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
        if (convertedBean == null) {
          throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
        }
        return convertedBean;
      }
      catch (TypeMismatchException ex) {
        if (logger.isTraceEnabled()) {
          logger.trace("Failed to convert bean '" + name + "' to required type '" +
              ClassUtils.getQualifiedName(requiredType) + "'", ex);
        }
        throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
      }
    }
    return (T) bean;
  }
...
}

三、总结

Spring IOC还有很多内容,本文只是管中窥豹,其他的部分将继续在后续的文章中进行详细介绍。

相关文章
|
4月前
|
搜索推荐 JavaScript Java
基于springboot的儿童家长教育能力提升学习系统
本系统聚焦儿童家长教育能力提升,针对家庭教育中理念混乱、时间不足、个性化服务缺失等问题,构建科学、系统、个性化的在线学习平台。融合Spring Boot、Vue等先进技术,整合优质教育资源,提供高效便捷的学习路径,助力家长掌握科学育儿方法,促进儿童全面健康发展,推动家庭和谐与社会进步。
|
5月前
|
缓存 Java 开发者
【Spring】原理:Bean的作用域与生命周期
本文将围绕 Spring Bean 的作用域与生命周期展开深度剖析,系统梳理作用域的类型与应用场景、生命周期的关键阶段与扩展点,并结合实际案例揭示其底层实现原理,为开发者提供从理论到实践的完整指导。
674 22
|
5月前
|
人工智能 Java 开发者
【Spring】原理解析:Spring Boot 自动配置
Spring Boot通过“约定优于配置”的设计理念,自动检测项目依赖并根据这些依赖自动装配相应的Bean,从而解放开发者从繁琐的配置工作中解脱出来,专注于业务逻辑实现。
1912 0
|
4月前
|
XML Java 测试技术
《深入理解Spring》:IoC容器核心原理与实战
Spring IoC通过控制反转与依赖注入实现对象间的解耦,由容器统一管理Bean的生命周期与依赖关系。支持XML、注解和Java配置三种方式,结合作用域、条件化配置与循环依赖处理等机制,提升应用的可维护性与可测试性,是现代Java开发的核心基石。
|
4月前
|
XML Java 应用服务中间件
【SpringBoot(一)】Spring的认知、容器功能讲解与自动装配原理的入门,带你熟悉Springboot中基本的注解使用
SpringBoot专栏开篇第一章,讲述认识SpringBoot、Bean容器功能的讲解、自动装配原理的入门,还有其他常用的Springboot注解!如果想要了解SpringBoot,那么就进来看看吧!
549 3
|
6月前
|
Java 关系型数据库 数据库
深度剖析【Spring】事务:万字详解,彻底掌握传播机制与事务原理
在Java开发中,Spring框架通过事务管理机制,帮我们轻松实现了这种“承诺”。它不仅封装了底层复杂的事务控制逻辑(比如手动开启、提交、回滚事务),还提供了灵活的配置方式,让开发者能专注于业务逻辑,而不用纠结于事务细节。
|
8月前
|
XML 人工智能 Java
Spring IOC 到底是什么?
IOC(控制反转)是一种设计思想,主要用于解耦代码,简化依赖管理。其核心是将对象的创建和管理交给容器处理,而非由程序直接硬编码实现。通过IOC,开发者无需手动new对象,而是由框架负责实例化、装配和管理依赖对象。常见应用如Spring框架中的BeanFactory和ApplicationContext,它们实现了依赖注入和动态管理功能,提升了代码的灵活性与可维护性。
221 1
|
7月前
|
缓存 安全 Java
Spring 框架核心原理与实践解析
本文详解 Spring 框架核心知识,包括 IOC(容器管理对象)与 DI(容器注入依赖),以及通过注解(如 @Service、@Autowired)声明 Bean 和注入依赖的方式。阐述了 Bean 的线程安全(默认单例可能有安全问题,需业务避免共享状态或设为 prototype)、作用域(@Scope 注解,常用 singleton、prototype 等)及完整生命周期(实例化、依赖注入、初始化、销毁等步骤)。 解析了循环依赖的解决机制(三级缓存)、AOP 的概念(公共逻辑抽为切面)、底层动态代理(JDK 与 Cglib 的区别)及项目应用(如日志记录)。介绍了事务的实现(基于 AOP
256 0
|
7月前
|
监控 架构师 NoSQL
spring 状态机 的使用 + 原理 + 源码学习 (图解+秒懂+史上最全)
spring 状态机 的使用 + 原理 + 源码学习 (图解+秒懂+史上最全)
|
XML Java 数据格式
京东一面:spring ioc容器本质是什么? ioc容器启动的步骤有哪些?
京东一面:spring ioc容器本质是什么? ioc容器启动的步骤有哪些?

热门文章

最新文章