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

本文涉及的产品
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 其实很多同学都想通过阅读框架的源码以汲取框架设计思想以及编程营养,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还有很多内容,本文只是管中窥豹,其他的部分将继续在后续的文章中进行详细介绍。

目录
打赏
0
0
0
0
328
分享
相关文章
Spring IOC—基于注解配置和管理Bean 万字详解(通俗易懂)
Spring 第三节 IOC——基于注解配置和管理Bean 万字详解!
123 26
【SpringFramework】Spring IoC-基于注解的实现
本文主要记录基于Spring注解实现IoC容器和DI相关知识。
68 21
【SpringFramework】Spring IoC-基于XML的实现
本文主要讲解SpringFramework中IoC和DI相关概念,及基于XML的实现方式。
119 69
【Spring】IoC和DI,控制反转,Bean对象的获取方式
IoC,DI,控制反转容器,Bean的基本常识,类注解@Controller,获取Bean对象的常用三种方式
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
本文详细介绍了Spring框架的核心功能,并通过手写自定义Spring框架的方式,深入理解了Spring的IOC(控制反转)和DI(依赖注入)功能,并且学会实际运用设计模式到真实开发中。
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
Spring bean的生命周期详解!
本文详细解析Spring Bean的生命周期及其核心概念,并深入源码分析。Spring Bean是Spring框架的核心,由容器管理其生命周期。从实例化到销毁,共经历十个阶段,包括属性赋值、接口回调、初始化及销毁等。通过剖析`BeanFactory`、`ApplicationContext`等关键接口与类,帮助你深入了解Spring Bean的管理机制。希望本文能助你更好地掌握Spring Bean生命周期。
283 1
Spring bean的生命周期详解!
本文详细介绍了Spring框架中的核心概念——Spring Bean的生命周期,包括实例化、属性赋值、接口回调、初始化、使用及销毁等10个阶段,并深入剖析了相关源码,如`BeanFactory`、`DefaultListableBeanFactory`和`BeanPostProcessor`等关键类与接口。通过理解这些核心组件,读者可以更好地掌握Spring Bean的管理和控制机制。
173 1
Spring的Bean生命周期中@PostConstruct注解
【8月更文挑战第3天】在Spring框架中,`@PostConstruct`注解标示Bean初始化完成后立即执行的方法。它在依赖注入完成后调用,适用于资源加载、属性设置等初始化操作。若方法中抛出异常,可能影响Bean初始化。与之对应,`@PreDestroy`注解的方法则在Bean销毁前执行,用于资源释放。
202 0
|
8月前
|
Spring Boot 启动源码解析结合Spring Bean生命周期分析
Spring Boot 启动源码解析结合Spring Bean生命周期分析
140 11

热门文章

最新文章

AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等