《Spring从0到1》:配置创建、注入bean原理

2023年 8月 7日 75.5k 0

手把手带你看spring的配置创建、注入以及获取bean。

看源码最好的方式就是定义一个最最基本的流程,从开始debug到你认为懂了为止。

bean的配置

最基本的spring配置是将bean配置在spring的配置文件中,该配置文件还可以配置spring的配置属性,虽然标签不是,但是spring会将其注入到指定的类中,因此不论标签如何,spring都会将配置文件中的属性转化成类属性,最终创建对应的对象。有的朋友可能已经注意到了:配置都是放在标签中的。

spring配置.jpg

bean的生成与注入

启动spring的入口之一就是创建 ClassPathXmlApplicationContext 对象:

//创建Spring容器的对象:ApplicationContext的实现类 ----> ClassPathXmlApplicationContext
//ApplicationContext就是表示Spring容器,我们可以通过容器获取对象
ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");

向下看之前不妨看一下该类的UML关系:

ClassPathXmlApplicationContext_UML.jpg

创建ClassPathXmlApplicationContext对象时就能看到整个spring创建对象的流程:

创建classpathxmlapplicationcontext.jpg
真正调用的是这里:
真正调用点.jpg
这里的setConfigLocations方法只是将传入的配置文件名注入到本类的configLocations字符串数组变量中。

真正的流程是在refresh方法中,该方法的实现其实是在父类AbstractApplicationContext中:

refresh调用点.jpg
将一些与主流程相关较小的代码剔除后如下:

public void refresh() throws BeansException, IllegalStateException {
   //在方法内对别的对象加锁,使得锁最小化。
   synchronized (this.startupShutdownMonitor) {
      //第一步就是创建bean的容器
      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

      prepareBeanFactory(beanFactory);

      try {
         
         postProcessBeanFactory(beanFactory);
         
         invokeBeanFactoryPostProcessors(beanFactory);

         registerBeanPostProcessors(beanFactory);

         finishBeanFactoryInitialization(beanFactory);
         
      } catch (BeansException ex) {...}

      finally {
         resetCommonCaches();
         contextRefresh.end();
      }
   }
}

逐步解析:

  • obtainFreshBeanFactory():

    obtainFreshBeanFactory方法.jpg
    其中:refreshBeanFactory() 才是创建beanFactory的关键:其在 AbstractApplicationContext 类中是抽象方法,需要子类实现,通常调用的是 AbstractRefreshableApplicationContext 类。

    refreshBeanFactory.jpg
    其中 loadBeanDefinitions(beanFactory) 是最主要的,在子类 AbstractXmlApplicationContext 中
    loadBeanDefinitions.jpg
    loadBeanDefinitions(beanFactory) 创建了 XmlBeanDefinitionReader 对象。该类封装了读配置文件的逻辑。随后就是调用 XmlBeanDefinitionReader的方法 loadBeanDefinitions :
    reader.jpg
    这个方法在其父类 AbstractBeanDefinitionReader 中实现:
    AbstractBeanDefinitionReader.jpg
    AbstractBeanDefinitionReader 将字符串类型的配置文件名转化为 Resource 对象,Resource是个接口,继承了InputStreamSource,Spring中对于文件的读取类都需实现该接口。
    而通过Resource加载类的方法是在子类 XmlBeanDefinitionReader 实现:
    loadBeanBefinitions(EncodedReource).jpg
    接着就是创建但是真正读配置文件的抽象类:BeanDefinitionDocumentReader。
    registerBeanDefinitons.jpg
    registerBeanDefinitions 在子类 DefaultBeanDefinitionDocumentReader 中实现:
    doRegisterBeanDefinitions.jpg
    然后挨个解析每一个标签
    parseBeanDefinitions.jpg
    通过工具类加载类定义.jpg
    这里的 BeanDefinitionHolder 要注意,这个就是解析bean标签的生成对象,可以看出,bean 标签里设置的属性都在该对象中,没有配置的属性会采用默认值(这也解释了spring中创建的对象默认是懒加载的)。
    DefinitionHolder对象.jpg
    随后将对象名和类定义放入【DefaultListableBeanFactory】的 beanDefinitionMap 中。

    而事实上,后续的流程都是针对 DefaultListableBeanFactory类的。
    BeanDefinitonReaderUtil.registerBeanDefinition.jpg
    放入BeanDefinitonMap.jpg
    就此,spring中一个完整的配置文件中bean的解析、注册就结束了!!!

  • prepareBeanFactory(beanFactory)

    该方法就只是为Spring的BeanFactory赋值。比如后置处理器,添加一些Spring内部对象等:

    /**
     * 配置BeanFactory的一些上下文属性,比如上下文类加载器和后置处理器
     * @param 需要赋值的beanFactory 
     */
    protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
       //使用调用类的类加载器
       beanFactory.setBeanClassLoader(getClassLoader());
       if (!shouldIgnoreSpel) {
          beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
       }
       beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
    
       // Configure the bean factory with context callbacks.
       beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
       beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
       beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
       beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
       beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
       beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
       beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
       beanFactory.ignoreDependencyInterface(ApplicationStartupAware.class);
    
       // BeanFactory interface not registered as resolvable type in a plain factory.
       // MessageSource registered (and found for autowiring) as a bean.
       beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
       beanFactory.registerResolvableDependency(ResourceLoader.class, this);
       beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
       beanFactory.registerResolvableDependency(ApplicationContext.class, this);
    
       // Register early post-processor for detecting inner beans as ApplicationListeners.
       beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
    
       // Detect a LoadTimeWeaver and prepare for weaving, if found.
       if (!NativeDetector.inNativeImage() && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
          beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
          // Set a temporary ClassLoader for type matching.
          beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
       }
    
       // 注册默认的环境类对象
       if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
          beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
       }
       if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
          beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
       }
       if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
          beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
       }
       if (!beanFactory.containsLocalBean(APPLICATION_STARTUP_BEAN_NAME)) {
          beanFactory.registerSingleton(APPLICATION_STARTUP_BEAN_NAME, getApplicationStartup());
       }
    }
    
  • invokeBeanFactoryPostProcessors(beanFactory):

    该方法主要是加载和实例化 BeanFactory 后置处理器(所有实现了 BeanFactoryPostProcessor 接口的类)。后置处理器可以在 Bean 实例化、属性填充、初始化和销毁等不同的阶段对 Bean 进行自定义的处理和增强。典型的后处理器就是org.mybatis.spring.mapper.MapperScannerConfigurer,该类将指定的mapper接口注册到mybatisConfiguration类的MapperRegistry属性中。

  • registerBeanPostProcessors(beanFactory):

    主要是将上一步实例化的后置处理器对象添加到 beanFactory 的 beanPostProcessors 变量中。

  • finishBeanFactoryInitialization(beanFactory):

    从方法名也能看出该方法是最终的一步:初始化所有的单例模式,所有的非懒加载的类。该方法内封装的其实就是之前构建的 ConfigurableListableBeanFactory 接口实现类的方法,spring中该接口的实现类用的是 DefaultListableBeanFactory

  • finishBeanFactoryInitialization方法.jpg
    preInstantiateSingletons.jpg
    可以看出,初始化类的时候是会根据类是否是工厂类而作出额外的初始化,最重要的还是 getBean方法。
    该方法是 ClassPathXmlApplication 的父类 AbstractApplicationContext 实现的:
    AbstractBeanDefinitionReader.getBean.jpg
    而 doGetBean 也是 AbstractBeanFactory 实现的:

    protected  T doGetBean(
          String name, @Nullable Class requiredType, @Nullable Object[] args, boolean typeCheckOnly)
          throws BeansException {
    
       String beanName = transformedBeanName(name);
       Object beanInstance;
    
       // 看看有无该类对象的缓存,有则直接返回
       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 + "'");
             }
          }
          beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
       }else {
          if (isPrototypeCurrentlyInCreation(beanName)) {
             throw new BeanCurrentlyInCreationException(beanName);
          }
    
          // 如果有父类的BeanFactory对象则调用父类BeanFactory独享的doGetBean方法。
          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);
          }
    
          StartupStep beanCreation = this.applicationStartup.start("spring.beans.instantiate")
                .tag("beanName", name);
          try {
             if (requiredType != null) {
                beanCreation.tag("beanType", requiredType::toString);
             }
             RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
             checkMergedBeanDefinition(mbd, beanName, args);
    
             // 先初始化要初始化对象依赖的对象,其实就是递归调用getBean。
             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);
                   }
                }
             }
    
             // 单例对象的初始化
             if (mbd.isSingleton()) {
                sharedInstance = getSingleton(beanName, () -> {
                   try {
                      return createBean(beanName, mbd, args);
                   }
                   catch (BeansException ex) {
                      destroySingleton(beanName);
                      throw ex;
                   }
                });
                beanInstance = 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);
                }
                beanInstance = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
             }
    
             else {
                //Spring2.0之后又引入了另外三种scope类型:request、session、global session类型
                //只能在只能在Web应用中使用,若只是后台进程的话则不会走该分支。
                String scopeName = mbd.getScope();
                if (!StringUtils.hasLength(scopeName)) {
                   throw new IllegalStateException("No scope name defined for bean '" + beanName + "'");
                }
                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);
                      }
                   });
                   beanInstance = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
                }
                catch (IllegalStateException ex) {
                   throw new ScopeNotActiveException(beanName, scopeName, ex);
                }
             }
          }
          catch (BeansException ex) {
             beanCreation.tag("exception", ex.getClass().toString());
             beanCreation.tag("message", String.valueOf(ex.getMessage()));
             cleanupAfterBeanCreationFailure(beanName);
             throw ex;
          }
          finally {
             beanCreation.end();
          }
       }
    
       return adaptBeanInstance(name, beanInstance, requiredType);
    }
    

    doGetBean 方法是先看看该对象是否已经初始化,如果没有在创建并初始化,值得注意的是,其是先创建并初始化当前要创建的对象的依赖(还是调用doGetbean),最后再根据对象类型分开创建,但是核心是调用 父类 AbstractAutowireCapableBeanFactory 的 createBean 方法。
    createBean.jpg
    AbstractAutowireCapableBeanFactory.createBean.jpg
    createBeanInstance则很有意思,其是先判断是否由指定工厂创建,再有无注册的构造方法,最后才会通过反射获取该类的构造方法构造对象。
    AbstractAutowireCapableBeanFactory.createBeanInstance.jpg
    AbstractAutowireCapableBeanFactory.InstantiateBean.jpg
    instantiate方法在 SimpleInstantiationStrategy类中。
    SimpleInstantiationStrategy.instantiate.jpg
    而 BeanUtil.instantiateClass方法则是封装的的通过构造器获取对象。
    BeanUtil.instantiateClass.jpg
    由此,一个对象就被创建结束,而后虽然会对该对象进行一系列封装,但是归根结底,spring的bean创建还是上述这些过程。

    bean的获取

    其实通过 ClassPathXmlApplicationContext 对象获取指定类的对象的 getBean 方法其实就是第5步中的方法,对于非懒加载类对象就可以直接获取,而懒加载类的对象则在此刻构建。

    最后再附上一张用到的UML图:

    《Spring从0到1》:配置创建、注入bean原理-1

    相关文章

    JavaScript2024新功能:Object.groupBy、正则表达式v标志
    PHP trim 函数对多字节字符的使用和限制
    新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
    使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
    为React 19做准备:WordPress 6.6用户指南
    如何删除WordPress中的所有评论

    发布评论